Cannot drag&drop nodes and groups into swimlanes

I am trying to create a diagram from which to drag&drop into swimlanes nodes and groups.
I have used the samples from Vertical Swimlanes and Plantogram.

Using /go-1.8.14-debug.js

// These parameters need to be set before defining the templates.
    var MINLENGTH = 200;  // this controls the minimum length of any swimlane
    var MINBREADTH = 20;  // this controls the minimum breadth of any non-collapsed swimlane

    // some shared functions

    // this may be called to force the lanes to be laid out again
    function relayoutLanes() {
        myDiagram.nodes.each(function(lane) {
            if (!(lane instanceof go.Group)) return;
            if (lane.category === "Pool") return;
            lane.layout.isValidLayout = false;  // force it to be invalid
        });
        myDiagram.layoutDiagram();
    }

    // this is called after nodes have been moved or lanes resized, to layout all of the Pool Groups again
    function relayoutDiagram() {
        myDiagram.layout.invalidateLayout();
        myDiagram.findTopLevelGroups().each(function(g) { if (g.category === "Pool") g.layout.invalidateLayout(); });
        myDiagram.layoutDiagram();
    }

    // compute the minimum size of a Pool Group needed to hold all of the Lane Groups
    function computeMinPoolSize(pool) {
        // assert(pool instanceof go.Group && pool.category === "Pool");
        var len = MINLENGTH;
        pool.memberParts.each(function(lane) {
            // pools ought to only contain lanes, not plain Nodes
            if (!(lane instanceof go.Group)) return;
            var holder = lane.placeholder;
            if (holder !== null) {
                var sz = holder.actualBounds;
                len = Math.max(len, sz.height);
            }
        });
        return new go.Size(NaN, len);
    }

    // compute the minimum size for a particular Lane Group
    function computeLaneSize(lane) {
        // assert(lane instanceof go.Group && lane.category !== "Pool");
        var sz = computeMinLaneSize(lane);
        if (lane.isSubGraphExpanded) {
            var holder = lane.placeholder;
            if (holder !== null) {
                var hsz = holder.actualBounds;
                sz.width = Math.max(sz.width, hsz.width);
            }
        }
        // minimum breadth needs to be big enough to hold the header
        var hdr = lane.findObject("HEADER");
        if (hdr !== null) sz.width = Math.max(sz.width, hdr.actualBounds.width);
        return sz;
    }

    // determine the minimum size of a Lane Group, even if collapsed
    function computeMinLaneSize(lane) {
        if (!lane.isSubGraphExpanded) return new go.Size(1, MINLENGTH);
        return new go.Size(MINBREADTH, MINLENGTH);
    }


    // define a custom ResizingTool to limit how far one can shrink a lane Group
    function LaneResizingTool() {
        go.ResizingTool.call(this);
    }
    go.Diagram.inherit(LaneResizingTool, go.ResizingTool);

    LaneResizingTool.prototype.isLengthening = function() {
        return (this.handle.alignment === go.Spot.Bottom);
    };

    LaneResizingTool.prototype.computeMinPoolSize = function() {
        var lane = this.adornedObject.part;
        // assert(lane instanceof go.Group && lane.category !== "Pool");
        var msz = computeMinLaneSize(lane);  // get the absolute minimum size
        if (this.isLengthening()) {  // compute the minimum length of all lanes
            var sz = computeMinPoolSize(lane.containingGroup);
            msz.height = Math.max(msz.height, sz.height);
        } else {  // find the minimum size of this single lane
            var sz = computeLaneSize(lane);
            msz.width = Math.max(msz.width, sz.width);
            msz.height = Math.max(msz.height, sz.height);
        }
        return msz;
    };

    LaneResizingTool.prototype.resize = function(newr) {
        var lane = this.adornedObject.part;
        if (this.isLengthening()) {  // changing the length of all of the lanes
            lane.containingGroup.memberParts.each(function(lane) {
                if (!(lane instanceof go.Group)) return;
                var shape = lane.resizeObject;
                if (shape !== null) {  // set its desiredSize length, but leave each breadth alone
                    shape.height = newr.height;
                }
            });
        } else {  // changing the breadth of a single lane
            go.ResizingTool.prototype.resize.call(this, newr);
        }
        relayoutDiagram();  // now that the lane has changed size, layout the pool again
    };
    // end LaneResizingTool class


    // define a custom grid layout that makes sure the length of each lane is the same
    // and that each lane is broad enough to hold its subgraph
    function PoolLayout() {
        go.GridLayout.call(this);
        this.cellSize = new go.Size(1, 1);
        this.wrappingColumn = Infinity;
        this.wrappingWidth = Infinity;
        this.isRealtime = false;  // don't continuously layout while dragging
        this.alignment = go.GridLayout.Position;
        // This sorts based on the location of each Group.
        // This is useful when Groups can be moved up and down in order to change their order.
        this.comparer = function(a, b) {
            var ax = a.location.x;
            var bx = b.location.x;
            if (isNaN(ax) || isNaN(bx)) return 0;
            if (ax < bx) return -1;
            if (ax > bx) return 1;
            return 0;
        };
    }
    go.Diagram.inherit(PoolLayout, go.GridLayout);

    PoolLayout.prototype.doLayout = function(coll) {
        var diagram = this.diagram;
        if (diagram === null) return;
        diagram.startTransaction("PoolLayout");
        var pool = this.group;
        if (pool !== null && pool.category === "Pool") {
            // make sure all of the Group Shapes are big enough
            var minsize = computeMinPoolSize(pool);
            pool.memberParts.each(function(lane) {
                if (!(lane instanceof go.Group)) return;
                if (lane.category !== "Pool") {
                    var shape = lane.resizeObject;
                    if (shape !== null) {  // change the desiredSize to be big enough in both directions
                        var sz = computeLaneSize(lane);
                        shape.width = (!isNaN(shape.width)) ? Math.max(shape.width, sz.width) : sz.width;
                        shape.height = (isNaN(shape.height) ? minsize.height : Math.max(shape.height, minsize.height));
                        var cell = lane.resizeCellSize;
                        if (!isNaN(shape.width) && !isNaN(cell.width) && cell.width > 0) shape.width = Math.ceil(shape.width / cell.width) * cell.width;
                        if (!isNaN(shape.height) && !isNaN(cell.height) && cell.height > 0) shape.height = Math.ceil(shape.height / cell.height) * cell.height;
                    }
                }
            });
        }
        // now do all of the usual stuff, according to whatever properties have been set on this GridLayout
        go.GridLayout.prototype.doLayout.call(this, coll);
        diagram.commitTransaction("PoolLayout");
    };
    // end PoolLayout class


    function init() {
        if (window.goSamples) goSamples();  // init for these samples -- you don't need to call this
        var $$ = go.GraphObject.make;

        myDiagram =
            $$(go.Diagram, "myDiagramDiv",
                {
                    grid: $$(go.Panel,
                        "Grid",
                        $$(go.Shape, "LineH", { stroke: "lightgray", strokeWidth: 0.5 }),
                        $$(go.Shape, "LineH", { stroke: "gray", strokeWidth: 0.5, interval: 10 }),
                        $$(go.Shape, "LineV", { stroke: "lightgray", strokeWidth: 0.5 }),
                        $$(go.Shape, "LineV", { stroke: "gray", strokeWidth: 0.5, interval: 10 })
                    ),
                    //// start everything in the middle of the viewport
                    //initialContentAlignment: go.Spot.Center,
                    // use a custom ResizingTool (along with a custom ResizeAdornment on each Group)
                    resizingTool: new LaneResizingTool(),
                    // use a simple layout that ignores links to stack the top-level Pool Groups next to each other
                    layout: $$(PoolLayout),
                    // don't allow dropping onto the diagram's background unless they are all Groups (lanes or pools)
                    mouseDragOver: function(e) {
                        if (!e.diagram.selection.all(function(n) { return n instanceof go.Group; })) {
                            e.diagram.currentCursor = 'not-allowed';
                        }
                    },
                    mouseDrop: function(e) {
                        if (!e.diagram.selection.all(function(n) { return n instanceof go.Group; })) {
                            e.diagram.currentTool.doCancel();
                        }
                    },
                    allowDrop: true, // must be true to accept drops from the Palette
                    "draggingTool.dragsLink": true,
                    // a clipboard copied node is pasted into the original node's group (i.e. lane).
                    "commandHandler.copiesGroupKey": true,
                    // automatically re-layout the swim lanes after dragging the selection
                    "SelectionMoved": relayoutDiagram,  // this DiagramEvent listener is
                    "SelectionCopied": relayoutDiagram, // defined above
                    "animationManager.isEnabled": false,
                    // enable undo & redo
                    "undoManager.isEnabled": true,
                    "draggingTool.isGridSnapEnabled": true,
                });

        myDiagram._palettes = [];

        // this is a Part.dragComputation function for limiting where a Node may be dragged
        function stayInGroup(part, pt, gridpt) {
            // don't constrain top-level nodes
            var grp = part.containingGroup;
            if (grp === null) return pt;
            // try to stay within the background Shape of the Group
            var back = grp.resizeObject;
            if (back === null) return pt;
            // allow dragging a Node out of a Group if the Shift key is down
            if (part.diagram.lastInput.shift) return pt;
            var p1 = back.getDocumentPoint(go.Spot.TopLeft);
            var p2 = back.getDocumentPoint(go.Spot.BottomRight);
            var b = part.actualBounds;
            var loc = part.location;
            // find the padding inside the group's placeholder that is around the member parts
            var m = grp.placeholder.padding;
            // now limit the location appropriately
            var x = Math.max(p1.x + m.left, Math.min(pt.x, p2.x - m.right - b.width - 1)) + (loc.x-b.x);
            var y = Math.max(p1.y + m.top, Math.min(pt.y, p2.y - m.bottom - b.height - 1)) + (loc.y-b.y);
            return new go.Point(x, y);
        }

        myDiagram.nodeTemplate =
            $$(go.Node, "Auto",
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify),
                $$(go.Shape, "Rectangle",
                    { fill: "white", portId: "", cursor: "pointer", fromLinkable: true, toLinkable: true }),
                $$(go.TextBlock, { margin: 5 },
                    new go.Binding("text", "key")),
                { dragComputation: stayInGroup } // limit dragging of Nodes to stay within the containing Group, defined above
            );

        function groupStyle() {  // common settings for both Lane and Pool Groups
            return [
                {
                    layerName: "Background",  // all pools and lanes are always behind all nodes and links
                    background: "transparent",  // can grab anywhere in bounds
                    movable: true, // allows users to re-order by dragging
                    copyable: false,  // can't copy lanes or pools
                    avoidable: false,  // don't impede AvoidsNodes routed Links
                    minLocation: new go.Point(-Infinity, NaN),  // only allow horizontal movement
                    maxLocation: new go.Point(Infinity, NaN)
                },
                new go.Binding("location", "loc", go.Point.parse).makeTwoWay(go.Point.stringify)
            ];
        }

        // hide links between lanes when either lane is collapsed
        function updateCrossLaneLinks(group) {
            group.findExternalLinksConnected().each(function(l) {
                l.visible = (l.fromNode.isVisible() && l.toNode.isVisible());
            });
        }

        // each Group is a "swimlane" with a header on the left and a resizable lane on the right
        myDiagram.groupTemplate =
            $$(go.Group, "Vertical", groupStyle(),
                {
                    selectionObjectName: "SHAPE",  // selecting a lane causes the body of the lane to be highlit, not the label
                    resizable: true, resizeObjectName: "SHAPE",  // the custom resizeAdornmentTemplate only permits two kinds of resizing
                    layout: $$(go.LayeredDigraphLayout,  // automatically lay out the lane's subgraph
                        {
                            isInitial: false,  // don't even do initial layout
                            isOngoing: false,  // don't invalidate layout when nodes or links are added or removed
                            direction: 90,
                            columnSpacing: 10,
                            layeringOption: go.LayeredDigraphLayout.LayerLongestPathSource
                        }),
                    computesBoundsAfterDrag: true,  // needed to prevent recomputing Group.placeholder bounds too soon
                    computesBoundsIncludingLinks: false,  // to reduce occurrences of links going briefly outside the lane
                    computesBoundsIncludingLocation: true,  // to support empty space at top-left corner of lane
                    handlesDragDropForMembers: true,  // don't need to define handlers on member Nodes and Links
                    mouseDrop: function(e, grp) {  // dropping a copy of some Nodes and Links onto this Group adds them to this Group
                        if (!e.shift) return;  // cannot change groups with an unmodified drag-and-drop
                        // don't allow drag-and-dropping a mix of regular Nodes and Groups
                        if (!e.diagram.selection.any(function(n) { return n instanceof go.Group; })) {
                            var ok = grp.addMembers(grp.diagram.selection, true);
                            if (ok) {
                                updateCrossLaneLinks(grp);
                            } else {
                                grp.diagram.currentTool.doCancel();
                            }
                        } else {
                            e.diagram.currentTool.doCancel();
                        }
                    },
                    subGraphExpandedChanged: function(grp) {
                        var shp = grp.resizeObject;
                        if (grp.diagram.undoManager.isUndoingRedoing) return;
                        if (grp.isSubGraphExpanded) {
                            shp.width = grp._savedBreadth;
                        } else {
                            grp._savedBreadth = shp.width;
                            shp.width = NaN;
                        }
                        updateCrossLaneLinks(grp);
                    }
                },
                new go.Binding("isSubGraphExpanded", "expanded").makeTwoWay(),
                //new go.Binding("position", "pos", go.Point.parse).makeTwoWay(go.Point.stringify),
                //{ // what to do when a drag-over or a drag-drop occurs on a Group
                //    mouseDragEnter: function(e, grp, prev) { highlightGroup(grp, true); },
                //    mouseDragLeave: function(e, grp, next) { highlightGroup(grp, false); },
                //    mouseDrop: function(e, grp) {
                //        var ok = grp.addMembers(grp.diagram.selection, true);
                //        if (!ok) grp.diagram.currentTool.doCancel();
                //    }
                //},
                // the lane header consisting of a Shape and a TextBlock
                $$(go.Panel, "Horizontal",
                    { name: "HEADER",
                        angle: 0,  // maybe rotate the header to read sideways going up
                        alignment: go.Spot.Center },
                    $$(go.Panel, "Horizontal",  // this is hidden when the swimlane is collapsed
                        new go.Binding("visible", "isSubGraphExpanded").ofObject(),
                        $$(go.Shape, "Diamond",
                            { width: 8, height: 8, fill: "white" },
                            new go.Binding("fill", "color")),
                        $$(go.TextBlock,  // the lane label
                            { font: "bold 13pt sans-serif", editable: true, margin: new go.Margin(2, 0, 0, 0) },
                            new go.Binding("text", "text").makeTwoWay())
                    ),
                    $$("SubGraphExpanderButton", { margin: 5 })  // but this remains always visible!
                ),  // end Horizontal Panel
                $$(go.Panel, "Auto",  // the lane consisting of a background Shape and a Placeholder representing the subgraph
                    $$(go.Shape, "Rectangle",  // this is the resized object
                        { name: "SHAPE", fill: "white" },
                        new go.Binding("fill", "color"),
                        new go.Binding("desiredSize", "size", go.Size.parse).makeTwoWay(go.Size.stringify)),
                    $$(go.Placeholder,
                        { padding: 12, alignment: go.Spot.TopLeft }),
                    $$(go.TextBlock,  // this TextBlock is only seen when the swimlane is collapsed
                        { name: "LABEL",
                            font: "bold 13pt sans-serif", editable: true,
                            angle: 90, alignment: go.Spot.TopLeft, margin: new go.Margin(4, 0, 0, 2) },
                        new go.Binding("visible", "isSubGraphExpanded", function(e) { return !e; }).ofObject(),
                        new go.Binding("text", "text").makeTwoWay())
                )  // end Auto Panel
            );  // end Group

        // define a custom resize adornment that has two resize handles if the group is expanded
        myDiagram.groupTemplate.resizeAdornmentTemplate =
            $$(go.Adornment, "Spot",
                $$(go.Placeholder),
                $$(go.Shape,  // for changing the length of a lane
                    {
                        alignment: go.Spot.Bottom,
                        desiredSize: new go.Size(50, 7),
                        fill: "lightblue", stroke: "dodgerblue",
                        cursor: "row-resize"
                    },
                    new go.Binding("visible", "", function(ad) {
                        if (ad.adornedPart === null) return false;
                        return ad.adornedPart.isSubGraphExpanded;
                    }).ofObject()),
                $$(go.Shape,  // for changing the breadth of a lane
                    {
                        alignment: go.Spot.Right,
                        desiredSize: new go.Size(7, 50),
                        fill: "lightblue", stroke: "dodgerblue",
                        cursor: "col-resize"
                    },
                    new go.Binding("visible", "", function(ad) {
                        if (ad.adornedPart === null) return false;
                        return ad.adornedPart.isSubGraphExpanded;
                    }).ofObject())
            );

        myDiagram.groupTemplateMap.add("Pool",
            $$(go.Group, "Auto", groupStyle(),
                { // use a simple layout that ignores links to stack the "lane" Groups next to each other
                    layout: $$(PoolLayout, { spacing: new go.Size(0, 0) })  // no space between lanes
                },
                $$(go.Shape,
                    { fill: "white" },
                    new go.Binding("fill", "color")),
                $$(go.Panel, "Table",
                    { defaultRowSeparatorStroke: "black" },
                    $$(go.Panel, "Horizontal",
                        { row: 0, angle: 0 },
                        $$(go.TextBlock,
                            { font: "bold 16pt sans-serif", editable: true, margin: new go.Margin(2, 0, 0, 0) },
                            new go.Binding("text").makeTwoWay())
                    ),
                    $$(go.Placeholder,
                        { row: 1 })
                )
            ));

        myDiagram.linkTemplate =
            $$(go.Link,
                { routing: go.Link.AvoidsNodes, corner: 5 },
                { relinkableFrom: true, relinkableTo: true },
                $$(go.Shape),
                $$(go.Shape, { toArrow: "Standard" })
            );

        function highlightGroup(grp, show) {
            if (!grp) return;
            if (show) {  // check that the drop may really happen into the Group
                var tool = grp.diagram.toolManager.draggingTool;
                var map = tool.draggedParts || tool.copiedParts;  // this is a Map
                if (grp.canAddMembers(map.toKeySet())) {
                    grp.isHighlighted = true;
                    return;
                }
            }
            grp.isHighlighted = false;
        }

        // decide what kinds of Parts can be added to a Group
        myDiagram.commandHandler.memberValidation = function(grp, node) {
            if (grp instanceof go.Group && node instanceof go.Group) return false;  // cannot add Groups to Groups
            // but dropping a Group onto the background is always OK
            return true;
        };

myDiagram.groupTemplateMap.add("MyGroup", $$(go.Group, "Auto",
        {
            background: "transparent",
            ungroupable: true,
            // highlight when dragging into the Group
            mouseDragEnter: function (e, grp, prev) { GroupFunctions.highlightGroup(e, grp, true); },
            mouseDragLeave: function (e, grp, next) { GroupFunctions.highlightGroup(e, grp, false); },
            computesBoundsAfterDrag: true,
            // when the selection is dropped into a Group, add the selected Parts into that Group;
            // if it fails, cancel the tool, rolling back any changes
            mouseDrop: GroupFunctions.finishDrop,
            handlesDragDropForMembers: true,  // don't need to define handlers on member Nodes and Links
            // Groups containing Nodes lay out their members vertically
            layout:
            $$(go.GridLayout,
                {
                    wrappingColumn: 1, alignment: go.GridLayout.Position,
                    cellSize: new go.Size(1, 1), spacing: new go.Size(4, 4)
                })
        },
        new go.Binding("background", "isHighlighted", function (h) { return h ? "rgba(255,0,0,0.2)" : "transparent"; }).ofObject(),
        $$(go.Shape, "Rectangle",
            { fill: null, stroke: "#33D3E5", strokeWidth: 2 }),
        $$(go.Panel, "Vertical",  // title above Placeholder
            $$(go.Panel, "Horizontal",  // button next to TextBlock
                { stretch: go.GraphObject.Horizontal, background: "#33D3E5" },
                $$("SubGraphExpanderButton",
                    { alignment: go.Spot.Right, margin: 5 }),
                $$(go.TextBlock,
                    {
                        alignment: go.Spot.Left,
                        editable: true,
                        margin: 5,
                        font: "bold 16px sans-serif",
                        opacity: 0.75,
                        stroke: "#404040"
                    },
                    new go.Binding("text", "text").makeTwoWay())
            ),  // end Horizontal Panel
            $$(go.Placeholder,
                { padding: 5, alignment: go.Spot.TopLeft })
        )  // end Vertical Panel
    );  // end Group and call to add to template Map);

myDiagram.nodeTemplateMap.add("My node", return $$(go.Node, "Auto",
        {
            mouseDragEnter: function (e, node) {
                e.handled = true;
                node.findObject("SHAPE").fill = "red";
                highlightGroup(node.containingGroup, false);
            },
            mouseDragLeave: function (e, node) {
                node.updateTargetBindings();
            },
            mouseDrop: function (e, node) {  // disallow dropping anything onto an "item"
                node.diagram.currentTool.doCancel();
            }
        },
           $$(go.Shape, "RoundedRectangle", new go.Binding("fill")),
           $$(go.Panel, "Table", { defaultAlignment: go.Spot.Left },
           $$(go.TextBlock, { row: 0, column: 0, columnSpan: 2, font: "bold 12pt sans-serif" }, new go.Binding("text", "name")),
           $$(go.TextBlock, { row: 1, column: 0 }, new go.Binding("text", "operator").makeTwoWay()),
           $$(go.TextBlock, { row: 1, column: 1 }, " "),
           $$(go.TextBlock, { row: 1, column: 2 }, new go.Binding("text", "fontSize").makeTwoWay())),
           { dragComputation: SwimlaneGroupTemplate.stayInGroup }); // limit dragging of Nodes to stay within the containing Group, defined above);

relayoutLanes();

        initializePalettes();

        $$(function () {
            var inspector = new Inspector('myInfoDiv',
                myDiagram,
                {
                    properties: {
                        // key would be automatically added for nodes, but we want to declare it read-only also:
                        "key": { readOnly: true, show: Inspector.showIfPresent },
                        "name": { readOnly: true, show: Inspector.showIfPresent },
                        "category": { show: false },
                        // fill and stroke would be automatically added for nodes, but we want to declare it a color also:
                        "fill": { show: false, type: 'color' },
                        "stroke": { show: false, type: 'color' }
                    }
                });
        });
    }  // end init

    function initializePalettes() {
        myDiagram.model = new go.GraphLinksModel([
    { "key": "Pool", "text": "Pool", "isGroup": true, "category": "Pool", "loc": "0.5 26.59846649169922" },
    { "key": "Lane1", "text": "Lane 1", "isGroup": true, "group": "Pool", "color": "lightblue", "loc": "0.5 50.12131399000715", "size": "202 527" },
    { "key": "Lane2", "text": "Lane 2", "isGroup": true, "group": "Pool", "color": "lightgreen", "loc": "203.5 50.12131399000715", "size": "213.90087890625 527" },
    { "key": "Lane3", "text": "Lane 3", "isGroup": true, "group": "Pool", "color": "lightyellow", "size": "253 527", "loc": "418.5 50.12131399000715" },
    { "key": "Lane4", "text": "Lane 4", "isGroup": true, "group": "Pool", "color": "orange", "loc": "672.5 50.12131399000715", "size": "266 527" }
]);

        paletteDiv = new DiagramPalette("paletteDiv", myDiagram, [
    { key: 1, text: "My Group", isGroup: true, category: "MyGroup", group:"Lane1" },
    { category: "My Node", name: "My Node", fill: "#ACE600", group:'Lane1' }]
    }

In this case, everything I drag from the palette has group:undefined. If I manually change the group into “Lane1”, it can be dropped into the first lane.

If I uncomment

new go.Binding(“position”, “pos”, go.Point.parse).makeTwoWay(go.Point.stringify),
{ // what to do when a drag-over or a drag-drop occurs on a Group
mouseDragEnter: function(e, grp, prev) { highlightGroup(grp, true); },
mouseDragLeave: function(e, grp, next) { highlightGroup(grp, false); },
mouseDrop: function(e, grp) {
var ok = grp.addMembers(grp.diagram.selection, true);
if (!ok) grp.diagram.currentTool.doCancel();
}
},

I can drop only nodes and they take the group of the lane in which they are dropped, so no restriction to drop in the lane that they are assigned to. Also groups cannot be dragged into the swimlanes. Ideas? Thank you!!!

The principle technique for automatically adding dropped nodes to groups is the implementation of the mouseDrop event handler. That’s true in the Swim Lanes sample that you started from and in other samples such as Planogram.

Note how typical Group.mouseDrop event handlers call Group.addMembers.

I don’t know why you are having problems with drag-and-drop adding nodes to existing groups. Both the Planogram sample and the Regrouping sample do that already. Presumably you have set a break point in your mouseDrop event handler and stepped through what it does.

Thank you, Walter. Though, I cannot spot the mistake. I have started to write all code over again and now I can drag&drop both nodes and groups into swimlanes, but I get these errors:

go-1.8.14-debug.js:985 Uncaught TypeError: Cannot read property ‘Af’ of undefined
at mm (go-1.8.14-debug.js:985)
at E.layoutDiagram (go-1.8.14-debug.js:984)
at relayoutLanes (reviewprocess:269)
at init (reviewprocess:632)
at onload (reviewprocess:722)

go-1.8.14-debug.js:985 Uncaught TypeError: Cannot read property ‘Af’ of undefined
at mm (go-1.8.14-debug.js:985)
at E.layoutDiagram (go-1.8.14-debug.js:984)
at relayoutDiagram (reviewprocess:260)
at E.raiseDiagramEvent.E.Ja (go-1.8.14-debug.js:992)
at Uh.doMouseUp (go-1.8.14-debug.js:585)
at E.doMouseUp (go-1.8.14-debug.js:809)
at Nl.a.lo (go-1.8.14-debug.js:1021)

function relayoutDiagram() { myDiagram.layout.invalidateLayout(); myDiagram.findTopLevelGroups().each(function (g) { if (g.category === "Pool") g.layout.invalidateLayout(); }); myDiagram.layoutDiagram(); // error here }

function relayoutLanes() {
    myDiagram.nodes.each(function (lane) {
        if (!(lane instanceof go.Group)) return;
        if (lane.category === "Pool") return;
        lane.layout.isValidLayout = false;  // force it to be invalid
    });
    myDiagram.layoutDiagram(); // error here
}`

What is this Af property about?

I cannot tell what is undefined in your app. I suspect it is because there is something wrong with how the diagram is initialized.

The error appears to be complaining about Diagram.layout being undefined, but I don’t know how that is possible unless the Diagram has not been initialized yet.