Binding is not updating a Link shape when the model changes

I have a Link template that includes a binding for the stroke property of the Shape used to display the link.

go.Link,
    {
        selectable: false,
    },
    // use `Normal` routing except for links within a single table
    new go.Binding('routing', '', (linkData: IERDGraphLink) => {
        return linkData.from === linkData.to
            ? go.Link.AvoidsNodes
            : go.Link.Normal;
    }),
    new go.Binding('fromEndSegmentLength'),
    new go.Binding('toEndSegmentLength'),
    make(
        go.Shape,
        {
            fill: '#FFF',
        },
        new go.Binding('stroke', '', (linkData: IERDGraphLink) => {
            return linkData.isConnectedToHoveredTable ||
                linkData.isConnectedToSelectedTable
                ? HIGHLIGHTED_COLOR
                : DARK_BORDER_COLOR;
        }),
...

The stroke will appear correctly based on the initial value of the linkData but when that value is updated in the model, the stroke will not change. When I tried logging the value of the linkData it is still showing the initial values, not the updated values. I confirmed that the values are updating in the model by using the debugger.

Why is the updated linkData not being used in this binding?

Did you call Model.set (a.k.a. Model.setDataProperty) within a transaction? Something like:

myDiagram.model.commit(function(m) {
  m.set(link.data, "isConnectedToSelectedTable", !link.data.isConnectedToSelectedTable");
}, "changed link color");

Hmmm, if you are making this change within a Part.selectionChanged event handler, you do not need to execute a transaction. But you still need to call Model.set.

The reason I am confused is that I am doing something very similar within a Node template and it works fine. Is there any difference between doing this type of binding in a Node template versus a Link template?

I also should mention that I’m using a React component with the react-gojs package’s GojsDiagram as a child component. The model is part of the React component state. When the state is updated it re-renders, passing in the update model as a prop.

I am not calling Model.set anywhere. The GojsDiagram component is also a React component that uses a transaction when new props are passed in, in componentDidUpdate: react-gojs/GojsDiagram.tsx at master · xcomponent/react-gojs · GitHub

That calls the a method called applyUpdatesFromModel which then has the diagram model call applyIncrementalJson: react-gojs/GojsDiagram.tsx at master · xcomponent/react-gojs · GitHub and uses the new node data and link data.

Basically, i am just updating the model in my component and the GojsDiagram component should be handling things from there. Do you see anything in there that could be causing this issue?

There’s no reason it should work for nodes but not links.

What is the value of this.props.model.linkDataArray being passed in as modifiedLinkData
to the applyIncrementalJson method when you are making your updates? I imagine this could be where the problem lies.

Here’s a basic example of applyIncrementalJson to compare to: https://codepen.io/jhardy/pen/LwZYRq?editors=1010

Based on what I see on line 193 (react-gojs/GojsDiagram.tsx at master · xcomponent/react-gojs · GitHub), it is just passing all of the link data, not just data for the links that have changed.

One thing that looks like it may be a problem is that my linkData objects don’t have a key property. Since linkKeyProperty is set to key, I’m guessing that might be causing a problem. I will try adding a key property to the linkData when I get a chance to see if that makes a difference.

Yes, that is certainly the issue. The links must have keys such that the data can be kept in sync.

I added keys to the linkData object and that still did not fix the issue.

I tried replicating the same issue using the react-gojs sample (GitHub - nicolaserny/react-gojs-example: Example to show how to use gojs in a React/Redux environment) and I am seeing the same behavior where the links will not change even though the link data is changing in the model, so maybe this is a bug in the react-gojs package :(

In fact, the GojsDiagram component in react-gojs doesn’t even have a key property in the LinkModel. I tried adding it, just as I did in my own project, but it did not help.

Interesting, have you checked yet what exact modifiedLinkData value is being passed in applyIncrementalJson?

In applyUpdatesFromModel it uses the correct value of true.

44%20AM

But in the template binding function it always shows up as the whatever the initial value was, in this case false.

20%20AM

Would you be able to send us a reproducible sample? It may be a bug in the package, but we’d still like to take a look to see if there’s anything on the GoJS end.

Can you provide me an email address so that I can send a zip file to you with the code?

GoJS at our domain, nwoods.com.

Hmm, I tried that a few minutes ago and I got an automated reply that said it the email was rejected because of the attachment. See if you can download it from here: https://drive.google.com/open?id=1oICckI9BWflpbS5Xu0zM354NbIocWtIv

I took the react-gojs sample code and made some changes to demonstrate the problem I am running into. In this case, when you click the button to add a new child node, it marks the new link as new using an isNew property. When you add a another new node, it will also update existing links to have isNew be false. The links that are marked with isNew as true should show up red and the others should be black. However you will see that the links that are created with the isNew property set to true will never change to black, even after their isNew property has been changed to false.

I also added in a key property for links, which was missing in the original react-gojs sample code.

Ok got it. The model’s linkKeyProperty wasn’t actually set at initialization of your GojsDiagram component. This means that the model can’t get the key of the new link data passed in and so it can’t match the new data with existing model data. If you change render in your MyDiagram class to this, it should work as expected:

render() {
  return (
    <GojsDiagram
      diagramId="myDiagramDiv"
      model={this.props.model}
      linkKeyProperty="key"  // added this line
      createDiagram={this.createDiagram}
      className="myDiagram"
      onModelChange={this.props.onModelChange}
    />
  );
}

Nice, that worked! Thanks for you help with that.