Updating node data changes in nodeDataArray but not in node [Ionic] [Angular]

I have a diagram where I can drag node’s in from a palette. I want to view and edit a node’s data when I select the node with the use of an inspector (not using the inspector extension).

This is the ion input to view & change the name of a node, when clicking on a node the data will be put in selectedNodeData. This works and the name is shown in the input field.

<ion-input [(ngModel)]="selectedNodeData.name" (ionChange)="changeSelectedNodeData(selectedNodeData.key, 'name', $event.detail.value)"></ion-input>

When the input value changes, it is sent to the function changeSelectedNodeData(). This function accepts the key, property name (name in this case) and the value of the field.

changeSelectedNodeData(key: number, property: string, changedNodeData: any): void {
    this.diagramComponent.diagram.model.commit((m) => {
      m.setDataProperty(m.findNodeDataForKey(key), property, changedNodeData);
    }, 'change selected node data');
  }

This all runs fine, and the value is updated in the nodeDataArray, but it is not updated in the node in the diagram.

I have also tried this using produce shown in the angular example, this gives the same result where the nodeDataArray updates, but the node in the diagram does not

this.state = produce(this.state, draft => {
      draft.selectedNodeData = draft.diagramNodeData.find(nodeData => nodeData.key === key);
      draft.selectedNodeData[property] = changedNodeData;
    });

This is part of the state that has the diagram and palette data

public state = {
  diagramNodeData: [],
  diagramLinkData: [],
  diagramModelData: {},
  skipsDiagramUpdate: false,
};

The application is an Ionic project using AngularJS inside Electron.

What is your node template?

dia.nodeTemplateMap.add('HvacNode',
      $(go.Node, 'Auto',
        { desiredSize: new go.Size(112, 112),
          copyable: false,
          resizable: true,
        },
        new go.Binding('layerName', 'isSelected', s => s ? 'Foreground' : '').ofObject(),
        $(go.Panel, 'Auto',
          $(go.Shape, 'Rectangle',
            { fill: 'white', stroke: 'rgba(0, 0, 0, 1.5)' }),
          $(go.Panel, 'Vertical',
            $(go.TextBlock,
              {
                stretch: go.GraphObject.Horizontal, textAlign: 'center', font: '16pt',
                wrap: go.TextBlock.WrapDesiredSize, overflow: go.TextBlock.OverflowEllipsis },
              new go.Binding('text', 'name'))
          )
        ),
        $(go.Panel, 'Auto',
          new go.Binding('itemArray', 'portArray'),
          {
            stretch: go.GraphObject.Fill,
            itemTemplate:
              $(go.Panel,
                {
                  fromLinkable: true,
                  toLinkable: true,
                  cursor: 'pointer'
                },
                new go.Binding('portId', 'portId'),
                new go.Binding('alignment', 'alignment', go.Spot.parse),
                new go.Binding('fromSpot', 'side', v => nodePortSideConvert(v)),
                new go.Binding('toSpot', 'side', v => nodePortSideConvert(v)),
                $(go.Shape, 'Rectangle',
                  {
                    stroke: null, strokeWidth: 0,
                    desiredSize: portSize,
                    fill: 'black'
                  })
              )
          })
      ));

It’s odd that you only have a single element in a “Vertical” Panel (why bother with it?), but that’s OK.

More serious is that your “Auto” Panel with the Binding on the Panel.itemArray doesn’t have a main element. Don’t you want those ports to be aligned relative to something? Maybe you actually want to remove that nested “Auto” Panel and have the items be elements of the Node/“Auto” Panel, where the first nested “Auto” Panel would be the main element. If so, to make it clear, set GraphObject.isPanelMain to true on that Panel with the Shape surrounding the TextBlock.

The vertical panel is there since there would also be a picture there, but the picture has been temporarily removed.

I have also changed the panel for the itemArray. I’ve had issues where my link between 2 ports would actually connect to the node’s instead of the ports, that’s why I was messing around with them (this is fixed).

And I did indeed have the issue where the first element was not aligned. This was explained here https://gojs.net/latest/intro/itemArrays.html#DifferentPanelTypes.
That is why I temporarily put a port you see commented out below.

{name: 'Boiler', category: 'HvacNode', portArray: [
          // {portId: 'NULL', alignment: '0 0', side: 'NULL'},
          {portId: 'l1', alignment: '0 0.4', side: 'l'},
          {portId: 'l2', alignment: '0 0.6', side: 'l'},
          {portId: 'r1', alignment: '1 0.4', side: 'r'},
          {portId: 'r2', alignment: '1 0.6', side: 'r'},
        ]},

But my main issue is where the data would update in the nodeDataArray, but not in the node displayed in the diagram itself.

For the Panel with the ports specified by the itemArray that is bound to “portArray”, I was suggesting a design like that given in the last example in that Introduction section that you refer to: GoJS Item Arrays-- Northwoods Software

Something like this is a fairly common design, as you can see in some of our samples:

Node, "Spot"
    Panel, "Auto", { isPanelMain: true }
        Shape, "Rectangle"
        TextBlock
    ... ports created by itemTemplate copies bound to portArray items ...

Regarding updating, your node template binding and code are correct:

  $(go.TextBlock, . . .,
    new go.Binding('text', 'name'))
    this.diagramComponent.diagram.model.commit((m) => {
      m.setDataProperty(m.findNodeDataForKey(key), property, changedNodeData);
    }, 'change selected node data');

Although you might want to check to make sure that the call to Model.findNodeDataForKey actually did return the Object that you expect.

Remember that GoJS can mutate the data given to the model in the Model.nodeDataArray. References to objects that are not in the model will have no effect. But your calling Model.findNodeDataForKey or any similar look-up should be good. More discussion is at:
https://gojs.net/latest/intro/usingModels.html#IdentityAndReferences

I am unsure how to proceed, when testing, there is only one node in the diagram. And Model.findNodeDataForKey returns that node.

I printed the value of Model.findNodeDataForKey in different places in the process

changeSelectedNodeData(key: number, property: string, changedNodeData: any): void {
    this.diagramComponent.diagram.model.commit((m) => {

      console.group('Changing property');
      console.group('Before m.setDataProperty');
      console.log(m.findNodeDataForKey(key));
      console.groupEnd();

      m.setDataProperty(m.findNodeDataForKey(key), property, changedNodeData);

      console.group('After m.setDataProperty');
      console.log(m.findNodeDataForKey(key));
      console.groupEnd();

    }, 'change selected node data');

    console.group('After commit');
    console.log(this.diagramComponent.diagram.model.findNodeDataForKey(key));
    console.groupEnd();

    console.groupEnd();
  }

Which results in the following

(Output below is same as in screenshot, in the screenshot and code above I did cut off console.log(this.diagramComponent.diagram.model.toJson());, and there is also the modifiedNodeData that got called.)

diagram-visualisation.component.ts:497 Changing property
diagram-visualisation.component.ts:498 Before m.setDataProperty
diagram-visualisation.component.ts:499 {name: 'Placeholder', category: 'HvacNode', portArray: Array(4), __gohashid: 3882, key: -4}category: "HvacNode"key: -4name: "Placeholder2"portArray: Array(4)0: {portId: 'l1', alignment: '0 0.4', side: 'l', __gohashid: 3662}1: {portId: 'l2', alignment: '0 0.6', side: 'l', __gohashid: 3666}2: {portId: 'r1', alignment: '1 0.4', side: 'r', __gohashid: 3670}3: {portId: 'r2', alignment: '1 0.6', side: 'r', __gohashid: 3674}__gohashid: 3655length: 4[[Prototype]]: Array(0)__gohashid: 3882[[Prototype]]: Object
diagram-visualisation.component.ts:504 After m.setDataProperty
diagram-visualisation.component.ts:505 {name: 'Placeholder2', category: 'HvacNode', portArray: Array(4), __gohashid: 3882, key: -4}category: "HvacNode"key: -4name: "Placeholder2"portArray: Array(4)0: {portId: 'l1', alignment: '0 0.4', side: 'l', __gohashid: 3662}1: {portId: 'l2', alignment: '0 0.6', side: 'l', __gohashid: 3666}2: {portId: 'r1', alignment: '1 0.4', side: 'r', __gohashid: 3670}3: {portId: 'r2', alignment: '1 0.6', side: 'r', __gohashid: 3674}__gohashid: 3655length: 4[[Prototype]]: Array(0)__gohashid: 3882[[Prototype]]: Object
diagram-visualisation.component.ts:482 {modifiedNodeData: Array(1)}modifiedNodeData: Array(1)0: {name: 'Placeholder2', category: 'HvacNode', portArray: Array(4), key: -4}length: 1[[Prototype]]: Array(0)[[Prototype]]: Object
diagram-visualisation.component.ts:510 After commit
diagram-visualisation.component.ts:511 {name: 'Placeholder2', category: 'HvacNode', portArray: Array(4), __gohashid: 3882, key: -4}category: "HvacNode"key: -4name: "Placeholder2"portArray: Array(4)0: {portId: 'l1', alignment: '0 0.4', side: 'l', __gohashid: 3662}1: {portId: 'l2', alignment: '0 0.6', side: 'l', __gohashid: 3666}2: {portId: 'r1', alignment: '1 0.4', side: 'r', __gohashid: 3670}3: {portId: 'r2', alignment: '1 0.6', side: 'r', __gohashid: 3674}__gohashid: 3655length: 4[[Prototype]]: Array(0)__gohashid: 3882[[Prototype]]: Object
diagram-visualisation.component.ts:516 { "class": "GraphLinksModel",
  "linkKeyProperty": "key",
  "linkFromPortIdProperty": "fromPort",
  "linkToPortIdProperty": "toPort",
  "nodeDataArray": [{"name":"Placeholder2","category":"HvacNode","portArray":[{"portId":"l1","alignment":"0 0.4","side":"l"},{"portId":"l2","alignment":"0 0.6","side":"l"},{"portId":"r1","alignment":"1 0.4","side":"r"},{"portId":"r2","alignment":"1 0.6","side":"r"}],"key":-4}],
  "linkDataArray": []}

This seems very odd, unless I’m missing something, because what you are writing looks fine and should change the model and then update the node via your data binding.

What if you try an exceedingly simple example instead in your code, replacing template a model with just:

  myDiagram.nodeTemplate =
    new go.Node("Auto") 
      .add(new go.Shape()
        .bind("fill", "color"))
      .add(new go.TextBlock({ margin: 8 })
        .bind("text", "name"));

  myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, name: "Alpha", color: "lightblue" },
      { key: 2, name: "Beta", color: "orange" }
    ]);

And simplifying your model change to just:

    var key = 1;
    var property = "name";
    var changedNodeData = "new name";
    myDiagram.model.commit((m) => {
      m.setDataProperty(m.findNodeDataForKey(key), property, changedNodeData);
    }, 'change selected node data');

that code live: https://codepen.io/simonsarris/pen/bGLVQzx?editors=1010

Does that scenario work? It should let us narrow down if this is a typo somewhere or a problem related to Angular/Ionic

Apologies for the delayed response, after the weekend running the code again, I was able and still am able to change the data. I tried to figure out what made it work, but I am still unsure what did the trick, since the code above and the code used for updating data currently is still the same.

Not the best outcome, as I would’ve liked to figure out what was causing the problem.
Thank you for your time.