When does "merge data" transaction occur?

Hi,

I recently noticed that our app’s strange behavior.
After manipulating diagram (ex. move node, delete node, etc), undo (press Ctrl-Z) does not work, but once more press Ctrl-Z, undo works correctly.
(i.e. to undo we need to press Ctrl-Z twice)

To see what happened, I wrote following code to see undoManager’s transaction history.

const histLen = diagram.undoManager.history.length;
console.log(`undoManager.history.length=${diagram.undoManager.history.length}`);
console.log(`undoManager.historyIndex=${diagram.undoManager.historyIndex}`);
for (let i=0; i<histLen; i++) {
    const hist: go.Transaction = diagram.undoManager.history.get(i);
    console.log(`[${i}] ${hist.name}`);
}

after doing following manipulation, I run above code.
then I get this.

[manipulation]
(1) move node
(2) move node
(3) delete node
(4) mode node

[result]

undoManager.history.length=10
undoManager.historyIndex=9
[0] load initial network
[1] merge data
[2] Move
[3] merge data
[4] Move
[5] merge data
[6] deleteSelection
[7] merge data
[8] Move
[9] merge data

Probably because of “merge data” transaction, we need to press Ctrl-Z twice.

[Q1] What is “merge data” transaction? and what (when) makes this insert into history list?

[Q2] Is there any way to suppress “merge data” transaction?

Our app uses GoJS-React. and I hold nodeDataArray and linkDataArray within React’s state (useState), and I supply these 2 states to ReactDiagram’s property like this.

when doing something, I call setNodeDataArray() or setLinkDataArray() to update node/link.

I guess this architecture is what’s causing this strange ‘merge data’ transaction…?

const [nodeDataArray, setNodeDataArray] = React.useState<INexNodeData[]>([]);
const [linkDataArray, setLinkDataArray] = React.useState<INexLinkData[]>([]);

...

return (
              <ReactDiagram
                divClassName="diagram-component"
                initDiagram={initDiagram}
                nodeDataArray={nodeDataArray}
                linkDataArray={linkDataArray}
            />
);

Takuya.

When I try running our gojs-react-basic sample after adding this Model Changed listener in the Diagram initialization:

          "ModelChanged": e => console.log(e.toString())

I see all of the model ChangedEvents and all of the Transactions that occur. There’s no transaction for doing merges when the user makes changes within the diagram. However, there should be such a transaction when making a change to React state that the diagram should be seeing.

Perhaps you are not setting or observing the skipsDiagramUpdate property, to control whether changes in the props should be processed by the diagram component to update the Diagram’s Model.

Thanks, walter.

I checked my code and found as you said, yes. I didn’t write anything about skipDiagramUpdate property. so I changed my code to followinig.

        return (
            <ReactDiagram
                ref={ref}
                divClassName="diagram-component"
                initDiagram={initDiagram}
                nodeDataArray={nodeDataArray}
                linkDataArray={linkDataArray}
                skipsDiagramUpdate={true}
            />
        );

I added skipsDiagramUpdate={true}, that means, with my understand, to skip GoJS’s model update via ReactDiagram’s property (like nodeDataArray, linkDataArray). is that correct?

but sadly this change has no effect.
history log still shows merge data transaction.

Next I tried skipDiagramUpdate={false}, but history log didn’t changed.

Seems skipDiagramUpdate property has no effect to control transaction history…

Takuya.

According to ChatGPT, merge data transaction arises when model.setDataProperty is called.

I call this method everywhere, to update model and change diagram’s view correctly.

When does the "merge data" transaction occur?

  1. Direct data updates
  • When you make direct changes to the GoJS model using methods like model.setDataProperty or model.addNodeData, the changes are recorded under the "merge data" transaction.
  • For example:
diagram.model.setDataProperty(nodeData, "key", "newKey");

This operation will result in a transaction with the name "merge data".


and also ChatGPT says that to prevent adding history to transaction is, stop/start UndoManager manually like this:

diagram.model.undoManager.isEnabled = false; // Disable UndoManager

diagram.model.setDataProperty(nodeData, "key", "newKey"); // Update data

diagram.model.undoManager.isEnabled = true; // Re-enable UndoManager

I will look for good solution…

You need to set that skipDiagramUpdate property to true when your component is updating your app’s props, so that those changes aren’t merged back again into the diagram model, hopefully not having any effect, but at least wasting time and a transaction.