Initialization sequence when using gojs-angular 2

I have yet another issue with my gojs-angular 2 upgrade.

Basically I end up with duplicated node in the state (not in the diagram model). I cannot reproduce this issue with the provided sample. However this is what happens with the callstack :

In the provided sample that works :

  1. ngAfterViewInit in diagram-component.ts is called and inside there is a call to :
 // initialize the diagram model with the provided node / link / model data
    NgDiagramHelper.initializeModel(this.diagram, this.nodeDataArray, this.linkDataArray, this.modelData);
  1. inside ng-diagram-helper.ts the model change event is emitted :
component.modelChange.emit(dataChanges);
  1. in app.component.ts diagramModelChange function is called and the state is “produced” :
 public diagramModelChange = function (changes: go.IncrementalData)  { ... }
  1. finally in app.component, the code I was provided with in my previous ticket is called :
this.myDiagramComponent.diagram.delayInitialization(() => {
      this.state = produce(this.state, draft => {
        draft.diagramNodeData = data.nodeDataArray;
        draft.diagramLinkData = data.linkDataArray;
        draft.skipsDiagramUpdate = false;
      });
    });

Now, in my real app, the sequence is different :

  1. same
  2. same
  3. the delayInitialization is called instead of diagramModelChange:
this.myDiagramComponent.diagram.delayInitialization(() => {
      this.state = produce(this.state, draft => {
        draft.diagramNodeData = data.nodeDataArray;
        draft.diagramLinkData = data.linkDataArray;
        draft.skipsDiagramUpdate = false;
      });
    });

4.diagramModelChange is called and the following produces duplicated node :
draft.diagramNodeData = DataSyncService.syncNodeData(changes, draft.diagramNodeData, appComp.observedDiagram.model) as any;

I also notice the following error in the console right after :

Error: NG0100: ExpressionChangedAfterItHasBeenCheckedError: Expression has changed after it was checked. Previous value: ‘[object Object],[object Object],[object Object]’. Current value: ‘[object Object],[object Object],[object Object],[object Object],[object Object]’… Find more at Angular

I have compared my code many times with the sample and I cannot figure out what could possibly be different. Any idea where to look at ?

Hmm yes, I’ve done some thinking on what I gave you yesterday, it may not be the best approach.

I’ll look into this today, thanks for flagging

As long as you are using gojs-angular v2.03 or later, you have access to a method on DiagramComponent called clear. This makes it so the next state update is treated as diagram initialization (and all prior nodes / links are cleared). You should call this instead of wrapping your produce code in delayInitialization (as I erroneously told you to do yesterday)

As for the error you’re getting in the console – it’s an annoying one to to debug. See: Angular

One way around it I found: use the ngAfterContentInit lifecycle hook instead of the ngAfterViewInit hook in AppComponent. Here’s my full code for that:

public ngAfterContentInit(): void {
    const data = JSON.parse(`{ "class": "GraphLinksModel",
    "nodeKeyProperty": "id",
    "linkKeyProperty": "key",
    "linkFromPortIdProperty": "fromPort",
    "linkToPortIdProperty": "toPort",
    "modelData": {"prop":"value"},
    "nodeDataArray": [
  {"id":"Alpha","text":"Alpha","color":"red"},
  {"id":"Beta","text":"Beta","color":"orange"},
  {"id":"Gamma","text":"Gamma","color":"lightgreen"},
  {"id":"Delta","text":"Delta","color":"pink"}
  ],
    "linkDataArray": [
  {"key":-1,"from":"Alpha","to":"Beta","fromPort":"r","toPort":"1"},
  {"key":-2,"from":"Alpha","to":"Gamma","fromPort":"b","toPort":"t"},
  {"key":-3,"from":"Beta","to":"Beta"},
  {"key":-4,"from":"Gamma","to":"Delta","fromPort":"r","toPort":"l"},
  {"key":-5,"from":"Delta","to":"Alpha","fromPort":"t","toPort":"r"}
  ]}`);


    this.myDiagramComponent.clear(); // IMPORTANT!
    this.state = produce(this.state, draft => {
      draft.diagramNodeData = data.nodeDataArray;
      draft.diagramLinkData = data.linkDataArray;
    });
  }

Note: Only use the clear method when you want to treat a state update as diagram model initialization. For future state updates, do not use it.

I tried your solution and I end up with an exception. You can reproduce it in the go-js angular basic sample.

I replaced ngAfterViewInit with ngAfterContentInit. I removed the delayed intialization we added yesterday and replaced with that clear() method call.

Now if I change a value in the inspector, I get an exception on that line in the inspectorChange handler :

 console.log(this.observedDiagram.model.toJson());

exception:
Cannot read properties of null (reading ‘model’)

this.observedDiagram is now null.

This is obviously a problem when I want to save my diagram because I try to do : this.observedDiagram.model.toJson() and this fails with the same error.

Any idea ?

Ah I fixed it. Moved that code back to ngAfterViewInit :

 public ngAfterViewInit(): void {
    if (this.observedDiagram) { return; }

    this.observedDiagram = this.myDiagramComponent.diagram;
  }

the rest is in ngAfterContentInit. Works fine now. Will keep testing the rest of my app with the new version. Thanks