Inspector changes do not update data correctly (Angular)

Hi!
I’m using Angular and gojs-angular. I have an inspector which in simplified form is similar to the one shown in GoJS Angular basic demo. It’s form has two fields - first changes text of given node, second changes template of a node (node should change it’s apperance). Here is my code that handles inspector changes (it is nearly the same as the code in demo).

handleInspectorChange(data) {
    const key = data.key;

    let index = null;
    for (let i = 0; i < this.graphNodeData.length; i++) {
      const entry = this.graphNodeData[i];
      if (entry.key && entry.key === key) {
        index = i;
      }
    }

    if (index >= 0) {
      this.skipsDiagramUpdate = false;
      this.graphNodeData[index] = { ...data };
    }
  }

When I change the text of a node it works only once - after changing it second time, arrays synchronized by GoJS-Angular DataSyncService (this.graphNodeData present in my component and model.nodeDataArray) are out of sync, as shown below. After I change the category of a node it is synchronized again, however with this approach diagramModelChange() responsible for syncing those arrays is not called at all.

I’ve tried diffrent approaches such as:

    if (index >= 0) {
      const diagram = this.graphComponent.diagram;
      this.skipsDiagramUpdate = false;
      
      diagram.startTransaction();
      diagram.model.assignAllDataProperties(this.graphNodeData[index], data);
      diagram.updateAllTargetBindings();
      diagram.commitTransaction('update');
    }

This calls diagramModelChange() function and updates this.graphNodeData, but does not update model.nodeDataArray at all. Am I doing something wrong? What might be the problem?

First, ensure the text you are changing will change any Node keys – since the keys are used to look up nodes in the arrays, changing one will make it impossible to keep them in sync.

If that’s not it, can you send me a minimal example of your issue? Maybe a small github repo or something like that? I am unable to reproduce this issue in gojs-angular-basic – in that sample, I can update Node color as many times as I like, undo / redo, and app data and diagram data stay in sync

Here is a repo that reproduces this problem: https://github.com/Hazzed5/gojs-inspector-example

Text present in the node is a subproperty and is bound by this function:

const makeTwoWaySubBinding = (
      targetname,
      sourcename,
      conversion?,
      backconversion?
    ) => {
      const bind = new go.Binding(targetname, "message");
      bind.mode = go.Binding.TwoWay;
      bind.converter = (message, target) => {
        const value = message[sourcename];
        if (value === undefined) return target[targetname];
        return typeof conversion === "function"
          ? conversion(value, target)
          : value;
      };
      bind.backConverter = (value, data, model) => {
        const message = data.message;
        if (model)
          model.setDataProperty(
            message,
            sourcename,
            typeof backconversion === "function"
              ? backconversion(value, message, model)
              : value
          );
        else
          message[sourcename] =
            typeof backconversion === "function"
              ? backconversion(value, message, model)
              : value;
        return message;
      };
      return bind;
    };

Maybe that’s the issue?

Hm, from a quick glance, I think the issue is probably having “complex” data (having “text” as a sub-property of “message”).

Behind the scenes, gojs-angular works by constantly observing the node and link data arrays you passed to your DiagramComponent (in your case, graphNodeData), checking if there are any changes to that Array, and if so, maybe merging the diagram.model data with the app data (graphNodeData). Usually, replacing some element of graphNodeData would trigger this change, but since you have nested data you are changing, it’s not always realizing these changes.

Try importing lodash in AppComponent, as you already are doing in your Inspector component, then when you replace an index of graphNodeData on handleInspectorChange, use lodash’s cloneDeep method. I just tried this and I think it works alright, let me know if you experience any problems.

import * as _ from "lodash";

......

handleInspectorChange(data) {
    const key = data.key;
    // find the entry in nodeDataArray with this key, replace it with newNodeData
    let index = null;
    for (let i = 0; i < this.graphNodeData.length; i++) {
      const entry = this.graphNodeData[i];
      if (entry.key && entry.key === key) {
        index = i;
      }
    }
    if (index >= 0) {
      this.skipsDiagramUpdate = false;
      this.graphNodeData[index] = _.cloneDeep(data);
    }
  }

It seems to work, thank you very much!