Undo does not sync data model

I am using gojs with angular as follows.

In the ngOnInit I am binding data to state.diagramLinkData , state.diagramNodeData and state.diagramModelData

Initial diagram as follows

Step 1. Expand “Track Section”

Step 2. Undo (ctrl +z) bring back previous state

Step 3. Expand “Train”

When expand what happen is bring down “Track Circuit” and “Driver” new nodes to data model. But now previously undone data “Signal” “Train Stopper” and “Trap Point” also getting displayed.
I assume this is because when undo it only undo the gojs view data but not underlying model data (linkDataArray, nodeDataArray).
Is there way to configure sync view and model when undo?

So is the problem is that you are doing the side-effects of an expansion more than once – both the first time (when you should) and on each redo?

That is what a Model Changed listener checks for ChangedEvent.isTransactionFinished and it is what updates the underlying data.
ChangedEvent | GoJS API
GoJS Changed Events -- Northwoods Software

You aren’t using gojs-angular, are you? That’s OK, you can reimplement some of that functionality in your app.

Hi Walter,

Yes, I am using gojs-angular in this case and also use gojs for some other graphs .
What I understand is I need to listen to the FinishedUndo event and get the new model data from the event and save the new data model again.

Keeping that on mind I tried to capture the FinishedUndo from addModelChangedListener but didn’t succeed.Looks like undo is not triggering modelChanged event. Am I following correct path?

I’m confused why any specific event listening is required at all. If you have a (modelChange) binding in your gojs-diagram as demonstrated in gojs-angular-basic, when you perform any operation that changes the model, such as undo, that function should fire, keeping your gojs model data and app-level data together.

For reference, this is the modelChange function in the basic sample – is yours different? Try the gojs-angular-basic project and note how this function fires on undo, and make sure yours is doing the same.

// When the diagram model changes, update app data to reflect those changes. Be sure to use immer's "produce" function to preserve immutability
  public diagramModelChange = function(changes: go.IncrementalData) {
    if (!changes) return;
    const appComp = this;
    this.state = produce(this.state, draft => {
      // set skipsDiagramUpdate: true since GoJS already has this update
      // this way, we don't log an unneeded transaction in the Diagram's undoManager history
      draft.skipsDiagramUpdate = true;
      draft.diagramNodeData = DataSyncService.syncNodeData(changes, draft.diagramNodeData, appComp.observedDiagram.model);
      draft.diagramLinkData = DataSyncService.syncLinkData(changes, draft.diagramLinkData, appComp.observedDiagram.model);
      draft.diagramModelData = DataSyncService.syncModelData(changes, draft.diagramModelData);
      // If one of the modified nodes was the selected node used by the inspector, update the inspector selectedNodeData object
      const modifiedNodeDatas = changes.modifiedNodeData;
      if (modifiedNodeDatas && draft.selectedNodeData) {
        for (let i = 0; i < modifiedNodeDatas.length; i++) {
          const mn = modifiedNodeDatas[i];
          const nodeKeyProperty = appComp.myDiagramComponent.diagram.model.nodeKeyProperty as string;
          if (mn[nodeKeyProperty] === draft.selectedNodeData[nodeKeyProperty]) {
            draft.selectedNodeData = mn;