removeArrayItem issues

I have a strange issue…

I listen the modelChange and particulary any removing on the linkDataArray. When this event is raised, I update each port to change the data used for the fill color (the current green circle).

onModelChange(e) {
  if (e.modelChange === 'linkDataArray' && e.change === go.ChangedEvent.Remove) {
    const link = e.oldValue;
    this.updatePorts(link);
  }
}

I delete the link

The findLinksConnected on each portId return no result. It’s correct. The port data is correctly updated.

I delete the left node port

Issue 1

I reset the diagram to this previous state (a browser reload or an undo). I delete the left node port (when I click on the right ‘-’ button) with the removeArrayItem method. The modelChange event is called but findLinksConnected return the link normaly deleted.

I delete a port with removeArrayItem but the findLinksConnected find a link normaly deleted. Why ?

Issue 2

Temporary I disabled the process linked to the linkLinksConnected and I set the fill property with the white color (In fact this process search if other links are connected to each ports, if found the color stay in green) :

model.setDataProperty(dataNode, 'fill', statusColor);

The dataNode is strictly the same like I delete the link (my first example), but In this case, the fill binding never receive the new value.

Do you have an idea or do you want I make a codepen ?

If the goal is to update the port color as links are connected or disconnected, I don’t think that necessarily warrants having that port state being held in the model.

Normally one implements Node.linkConnected and Node.linkDisconnected event handlers to modify the port’s Shape.fill or whatever visual indication that you want.

Ok I can try with this methods. But it seem the linkDisconnected is not call when a link is relinked on the same node but a different port.

Are you sure about that? We have a bunch of regression tests that exercise it. Perhaps we missed some case.

It’s the case ONLY if a link is relinked on the same node BUT a different port. When the link is relinked on another node the event is raised.

Ah, that’s interesting. Technically, the current behavior matches the documentation, since it only talks about “connected with this Node” and “disconnected from this Node”.

And you can get the event via Link.fromPortChanged and toPortChanged, although that might be a bit inconvenient.

So this seems to be a design bug, at least from your point of view. The question is whether we should change the behavior in the manner that you expect, and if so, whether to do it now or only in v2.0. I’ll have to think about that some more. Meanwhile you can use fromPortChanged and toPortChanged.

Yep but the behavior is allways strange :

A. When you move a link from a port to another port on the same node.

onLinkDisconnected : not called
toPortChanged : called

B. When you move a link from a port to another port BUT on another node :

onLinkDisconnected: called
toPortChanged : called twice (???)

C. When you delete a link :

onLinkDisconnected : called
toPortChanged: not called

In all case, a link is disconnected and the port has changed (to or from).

[EDIT] In B, the event is raised twice when a link is relinked on another node port :

onLinkToPortChanged(link, previousPort, newPort) {
  console.info('To Port Changed');
  console.info(link.toPort, link.toNode);
  console.info(link.toPort instanceof go.Node);

On the first call, the toPort (or fromPort) property of the link (the first argument) return the node and not the port.

To Port Changed
H {__gohashid: 5804, T: 12583939, Hc: 1, Dh: null, $b: ""…} 
H {__gohashid: 5804, T: 12583939, Hc: 1, Dh: null, $b: ""…}
true

The second call is correct :

To Port Changed
z {__gohashid: 5845, T: 4194307, Hc: 1, Dh: x, $b: ""…} 
H {__gohashid: 5804, T: 12608515, Hc: 1, Dh: null, $b: ""…}
false

That sounds about right.

When changing ports on the same node, by design the link has not been disconnected from the node, but obviously the Link.toPort has changed. If we were to change this for version 2.0, you would get a linkDisconnected event.

When changing nodes, you now get two toPortChanged events, once when connected to nothing, and then later when connecting it to a different node/port.

When deleting a link, the Link.toPort is not modified.

EDIT: I missed your edit. Yes, the link is temporarily connected to the RelinkingTool.temporaryToNode, before it is connected to the intended port/node, if it is changed at all.

Ok

Ok :) so it’s not an issue…

Yes, the programmer might want to change appearances during the relinking operation. You can see if the Node is in a Layer that is Layer.isTemporary, if you care.

A similar thing happens with the DraggingTool when dragging from another Diagram – the user drags around a temporary Node until a drop happens, if it happens at all.

It still isn’t clear to me whether we should change the behavior of the linkConnected and linkDisconnected events when a link changes the port but not the node. I can see arguments both ways. You know a good argument for. An argument against is that the name of the event, and the fact that it’s on a Node, implies that a link has been connected or disconnected from the Node, and that ports don’t really matter. Another argument against is that there would be a lot more events – you’d get two linkConnected events at a Node when connecting to a new port on a new node, once when setting the toNode and once when setting the toPortId.

In fact, when we link the port on another node port :

The first call, the link is the temporaryLink, the previousPort is the real previousPort,
The second call, the link is the final link, the previousPort is the temporaryNode,

link.toPort.layer.isTemporary return always false

Walter,

Another I dont understand with linkConnected vs to/fromPortChanged :

I create a new link, linkConnected is called, to/fromPortChanged too.

Step 1

onLinkConnected(node, link, portShape) {
  this.updatePortStatus(portShape);
}

updatePortStatus(portShape) {
  const port = portShape.findTemplateBinder();
  const model = this.diagram.model;
  model.setDataProperty(port.data, 'fill', '#FF0000');
  console.info(port.data.fill); // #FF0000
}

When a link is create, each port become red.

Step 2

I replace onLinkConnected with from/toPortChanged

onLinkFromPortChanged(link, previousPort, newPort) {
  this.updatePortStatus(link.toPort);
}

updatePortStatus(portShape) {
   ...
   console.info(port.data.fill); // #FF0000
}

The port.data is strictly the same but with step Step 2 the databinding is never called with the updated value, when and only when I create a new link (the same code work with relinked link).

new go.Binding('fill')

Is this possible to know with from/toPortChanged if this is a new link (no previousPort ?)

The case you describe now is similar to what you outlined above with deleting links. toPortChanged will not be called because the Link.toPort is not modified, it is just being connected for the first time.

I think you’ll need to use a combination of linkConnected + linkDisconnected, and fromPortChanged + toPortChanged to manage the various cases of links being created/deleted/relinked.