Problem with groups

Hi,

I’m working on a project where nodes haves ports to which a link can be attached. All is working well but i’m experiencing a problem when adding groups.

i can create a group just fine, but if i save it, and then reload it (by redrawing the model) i get an error:

List.removeAt:i is not in the range 0 <= i < length: 1

strangely enough, if i remove these lines of code:

diagram.model.linkFromPortIdProperty = 'from_port';
diagram.model.linkToPortIdProperty = 'to_port';

It renders just fine (but off course then the links aren’t linked as they should)

I also have textblocks and regular shapes (which don’t have the ports) and they’re giving me no problems.

any idea?

That’s odd. Could you help us to reproduce the problem? If you could either give us a minimal page or a CodePen, that would help.

i managed to reproduce it in codepen, here’s the example:

if you need anything more let me know!

I see. The problem is actually this:

    var groupTemplate = $(go.Group, 'Vertical', {
        // ...
        memberRemoved: function(event) {
          if (event.memberParts.count === 0) {
            diagram.skipsUndoManager = true;
            diagram.remove(event);
            diagram.skipsUndoManager = false;
          }
        },

As the specification says, memberRemoved cannot modify the group’s members, but it also shouldn’t try to modify the group itself (or produce any other non-cosmetic side-effects). We had given you this solution, so sorry about that.

Having the group delete itself when its last remember is removed can cause errors internally, which is what you’re seeing here.

Instead, if you want to have empty groups be deleted when they contain no more members, I suggest doing this:

function getDiagram($) {
 return $(go.Diagram, 'myDiagram', {
    // ... your other code here (omitted for brevity)
    "SelectionDeleted": deleteEmptyGroup  // defined below
  });
}

//  Deletes groups that have no members when members are deleted from within
function deleteEmptyGroup(e) {
  var diagram = e.diagram;
  e.subject.each(function(n) {
    var g = n.containingGroup;
    if (g.memberParts.count === 0) {
      diagram.remove(g);
    }
  })
}

Hi Simon,

Thanks for your reply, it was indeed the memberRemoved function, now that i disabled it it works fine. I’ll move the functionality to the selectionDeleted eventlistener.

It did work like this though, before i started adding ports to the nodes, just wanted to let you know.

Tim

One more question, what would be the best way to delete the group after the last member is dragged out of it? The selectionDeleted only handles nodes that are deleted.

You could also implement a “SelectionMoved” DiagramEvent listener.

  myDiagram =
    $(go.Diagram, . . .,
        { . . .,
          "SelectionMoved": deleteEmptyGroups,
          "SelectionDeleted": deleteEmptyGroups,
          . . .
        });

  function deleteEmptyGroups() {
      var groups = new go.Set(go.Group);
      myDiagram.nodes.each(function(n) { if (n instanceof go.Group && n.memberParts.count === 0) groups.add(n); });
      if (groups.count > 0) {
          myDiagram.removeParts(groups);
          deleteEmptyGroups();  // recurse in case of nested groups
      }
  }

As a separate issue, note the change to the function – it now recursively deletes groups, in case of nested groups.

Thanks for your reply, i was hoping to not have to iterate over all the nodes. for now its okay, but i think i’ll keep track of the group keys to have quick access to them.

I’m having another problem ATM.

When dragging a node out of a group it doesnt allways unbind to the group, the ‘group’ parameter still has the key of the old group, and the memberRemoved and containingGroupChanged functions will not fire. I’ll add a codepen example.

EDIT

I found out why i was having the problem. If dropped precisely on a link, the mouseDrop function of the link handles the event instead of the group. Is it possible to disable the mousedrop function, or let the action bubble op towards the group?

That is exactly why the Group.handlesDragDropForMembers property exists.

I tried setting that property, but it didn’t work, propably because links from outside of the group are in the way. I’ll keep trying, maybe i should set the layer of the group to foreground to make sure the links not connected to the group are not in the way

Yes, the Group cannot be responsible for Links that are not members of the Group.

But you could handle those mouseDrag… and mouseDrop events on such Links and invoke the code that your Group mouseDr… event handlers call. You either need to decide which Node to follow (whether Link.fromNode or Link.toNode) or you need to check which Group the InputEvent.documentPoint is in, if any.

Hi Walter,

I’m looking into the handlesDragDropForMembers property, but in the documentation it stated that it only handles the event in case there is no handler function set. I’n my case, all my nodes are groups, and they all have the same handlers, but if a group has been nested in an other group, the events should bubble up. is there any way i could do this easily?

Tim

You can implement that yourself. It’s all just JavaScript, so you can call your code with the containing Group.

Is it possible to auto select node in group?

myDiagram.commandHandler.deleteSelection()

A post was split to a new topic: Automatically selecting a Node in a Group