Loading from json leads to duplicated nodes in model

public load(json: string): void {

    if (!json) { return; }

    const data = JSON.parse(json);

    this.diagramNodeData = go.GraphLinksModel.fromJson(data).nodeDataArray;

    this.diagramLinkData = (go.GraphLinksModel.fromJson(data) as go.GraphLinksModel).linkDataArray;

    this.observedDiagram.model = go.Model.fromJson(data);

  }

I have the following scenario :

  1. draw two nodes and a link between them
  2. export to json
  3. add another link
  4. load the exported json
  5. add a link
  6. export and now the linkDataArray contains 4 links (the two added initially and the one added at point number 5, which is duplicated (same coordinates and properties values)

To fix that I changed the code to this :

public load(json: string): void {

    if (!json) { return; }

    const data = JSON.parse(json);

this.diagramNodeData = _.cloneDeep((go.GraphLinksModel.fromJson(data) as go.GraphLinksModel).nodeDataArray);

    this.diagramLinkData = _.cloneDeep((go.GraphLinksModel.fromJson(data) as go.GraphLinksModel).linkDataArray);

    this.observedDiagram.model = go.Model.fromJson(data);

  }

Now with the cloneDeep, I no longer have this issue.

but this leads to nodes disappearing from the diagram.

Am I missing something here ?

Have you read https://gojs.net/latest/intro/usingModels.html#IdentityAndReferences ? If you are getting duplicate instances of Node or Link in your Diagram, there must be duplicate instances of node data or link data in your GraphLinksModel.

The other way to look at it is that each separate Object in the Model.nodeDataArray will be a different Node (or Group or simple Part). So you should check the Array that is used by the model.

It is also very suspicious that you are deep-cloning the link data Array but not the node data Array. What are the key values declared in the node data Array’s Objects?

With further investigation it seems that the line causing the issue is the following :

this.observedDiagram.model = go.Model.fromJson(data);

I should have mentionned that my load method is called on two occasions :

  1. when the diagram is loaded the first time with an existing diagram model
  2. if the user loads a diagram from a json file

In case #1 the nodes appear for a split second and then they all disappear and only the links remain

In case #2 the nodes and the links are all in place, but if I move a node I notice it is no longer attached to its links.

If I remove the line of code, case #1 works just fine. Case #2, the nodes and links are loaded into model but the diagram is not updated. So I guess this is the one scenario I still need to fix. Any idea what I’m doing wrong ?

EDIT
@walter sorry I wrote my reply while you were replying to my first post. Yes, of course, I’am also deep cloning the node too, that was a typo in my first post

this.diagramNodeData = _.cloneDeep((go.GraphLinksModel.fromJson(data) as go.GraphLinksModel).nodeDataArray);

You need to decide whether you are operating on the model directly or if you are going through the gojs-angular component.

The former is what basically all of the samples do. They load a diagram by calling Model.fromJson (or constructing one programmatically) and then replacing the Diagram.model property. All changes to the model are performed by calling Model methods within a transaction.

If the latter is what you want to do, you should not be setting the Diagram.model property.

hum ok, then i guess I should stick with the angular component since I use Angular.

In this case, what am I not doing correctly when loading the data from json ? I guess it works when loading the page the first time because the load method is called from ngAfterViewInit. However when I call the load method to load data from json, this happens on a button click event. I suppose there is something I should do to update the diagram in this case ?

I’ll answer to myself :) I added a flag to check in which scenario we are. If loading the diagram after page loaded, I do not call

this.observedDiagram.model = go.Model.fromJson(data);

if loading json , then I call the line. Seems to be working fine like that. Does it make sense ?

I don’t understand why you would ever call Model.fromJson.

you are right, I could simplify my code as such :

const data = JSON.parse(json);

    this.diagramNodeData = _.cloneDeep(data.nodeDataArray);

    this.diagramLinkData = _.cloneDeep(data.linkDataArray);

    if (updateDiagram) {

     this.observedDiagram.model = go.Model.fromJson(data);

    }

I still need the line this.observedDiagram.model = go.Model.fromJson(data); for when I load the diagram from json file, otherwise the visual does not get updated. Is this normal ?

I think you shouldn’t have this code at all:

    if (updateDiagram) {
     this.observedDiagram.model = go.Model.fromJson(data);
    }

As it is now, it seems that initially the setting of Diagram.model is what is updating the diagram. So I’m wondering why app data changes are not being detected or merged into the diagram model and thus update the diagram’s nodes and links.

Look at how the DiagramComponent is defined in gojs-angular.
Is ngDoCheck being called?
Is the function passed to Diagram.delayInitiailization being called?

Yes, ngDoCheck is called all the time.

I have replaced

if (updateDiagram) {
     this.observedDiagram.model = go.Model.fromJson(data);
    }

with

    this.skipsDiagramUpdate = false;

And it works in all cases. I think this the correct way, no ?

Ah, so that was the problem. I’m glad you figured it out.