Dynamic ports and links - not in sync

Hi, I have a very complex case where upon clicking on a node, I first generate some ports for that node depending on some information in the node’s data object, and I then loop through my database of linksDataArray and add the links to the model data via model.addLinkData which are coming from or going to this node. The idea is that the diagram only ever displays links which are relevant to the user selected node or group. To summarise, the flow:

  1. user clicks on a node
  2. some ports (shapes with portId property) are generated dynamically and added to the node via panel.add function
  3. all the existing links in modelData.linkDataArray are removed, and new links revenant to the selected node are inserted into the modelData via model.addLinkData

The problem is that the newly inserted links do not connect themselves to the newly created ports the first time. However, upon deselecting and selecting the same node again (which now already has those ports formed) the newly added links do connect to their ports as desired. I am led to believe that the ports generation and links’ addition to the model is not in sync, such that when the links are added first time to the model, they do not “see” the newly generated ports. I have tried wrapping both these operations in different transactions but am getting the same result.

Could you please share with us what such a diagram would look like?

The diagram is on a react app in my local machine, but here are a couple of screenshots for explanation. The first image shows a node which isn’t clicked by the user (no ports, no links in the diagram.model.linkDataArray). The second diagram shows the same node after the user has clicked on it. You can see the additional text panel being displayed now, and the ports which surround words in this text box. In this screenshot the links are emerging correctly from their designated ports, but this is not happening the first time a node is being interacted with.

image

image

What happens if you try to do each of these actions in separate transactions?

myDiagram.commit(() => {
 // ... add the ports
});
myDiagram.commit(() => {
 // ... modify the link array
});

Does that change anything?

Also, do you have the animationManager enabled? Do you have a layout enabled? (isOngoing: true which is the default, etc)

It might be simpler if the detail section with ports is invisible and becomes visible when selected.

You could use a binding like this:
new go.Binding("visible", "isSelected").ofObject()

I have tried the separate transaction thing but this gives the same results. I am not altering the animations manager, so it is enabled by default. My diagram uses a LayeredDigraph layout and the isOngoing is set to true upon layout complete event. I have also noticed that this behaviour is quite random and that for most of the nodes, clicking on them the very first time can produce the desired result (links connecting with the newly created ports), and sometimes it does not do that. I have been unable to spot a reason or a pattern here.
I also see another strange behaviour, which is that when I remove the existing links on the diagram when the user selects a different node, many a times a few of those links still linger on in the diagram, even though the model.linkDataArray shows empty.

yes, the details section is actually invisible by default, and becomes visible only when its parent node is selected. I am achieving this by selecting this section by its name and setting its visible property to true.
node.findObject("DetailsSection").visible = true;

Try turning off the animation manger and try setting layout.isOngoing to false, just to narrow it down. In diagram settings you can write:

"animationManager.isEnabled": false

Okay so it’s much better now in the sense that only the first node that I interacted with gave that issue, and all the subsequent nodes had their links connecting correctly with their ports (although it is still weird why the exception for the first node). Other than that, I am still getting the “rogue links” issue where upon de-selecting a node, I often randomly see one or two of its links still persisting on the diagram, even though the model.linkDataArray is empty. This is a totally random behaviour, I might add. To remove the existing links upon de-selecting a node, I am looping through the model.linkDataArray , for each link, I call the diagram.model.removeLinkData() function.

How are you looping over the Array? Iterating over a collection while modifying it is potentially unreliable.

Besides, it is easier to just set GraphLinksModel.linkDataArray to [], an empty Array.

I was previously just setting the array to [] but I figured that that might be the reason why I am getting such issues, so I shifted to the remove link method, but I get the same results. This is the code that I am using to remove the links (please note that I was previously using model.linkDataArray, but tried a different approach with diagram.links to see different results, but couldn’t):

    while(linksItr.next()){
      const link = linksItr.value
      diagram.model.removeLinkData(link.data)
    }

GoJS iteration over Lists, Sets, and Maps normally signal an error if the collection is modified during iteration. (Set and Map were defined before ES6 Set and Map were even proposed.)

Are you not getting an exception?

no, that is not the issue, everything works fine.

Well, even if you are not getting an exception, it’s still undefined behavior, so I still recommend that you just set the GraphLinksModel.linkDataArray to an empty Array.

Thanks for letting me know. I have reverted to simply setting the GraphLinksModel.linkDataArray to empty array. However, the issue that I am facing appears to be of a completely different origin. It is very strange, and I don’t think it is anything other than a bug.

That is odd. Is there any way that you could provide us with a minimal reproducible test case sample?