toIncremental data does not match diagram model data


Our application heavily relies on the toIncrementalData calls of the GraphLinksModel. When testing a little bit more extensively with our application, I encountered inconsistencies between the diagram model and the data changes we receive with the toIncrementalData call.

Toy example:

<!DOCTYPE html>

  <title>Data changes</title>
  <meta charset="UTF-8">

<body onload="init()">
  <div id="app">
    <div id="diagram" style="border: solid 1px black; width:100%; height:300px"></div>
    <div style="display: flex;">
      <div style="width: 50%;">
        <h2>Model data</h2>
        <pre id="modeldata" style="height: 300px; overflow: scroll"></pre>
      <div style="width: 50%;">
        <pre id="datachanges" style="height: 300px; overflow: scroll"></pre>

  <script src=""></script>
  <script id="code">
    function init() {

      var $ = go.GraphObject.make;  // for conciseness in defining templates

      myDiagram = $(go.Diagram, "diagram",  // create a Diagram for the DIV HTML element
          "undoManager.isEnabled": true  // enable undo & redo

      // define a simple Node template
      myDiagram.nodeTemplate =
        $(go.Node, "Auto",  // the Shape will go around the TextBlock
          $(go.Shape, "RoundedRectangle", { strokeWidth: 0, fill: "white" },
            // Shape.fill is bound to
            new go.Binding("fill", "color")),
            { margin: 8, font: "bold 14px sans-serif", stroke: '#333' }, // Specify a margin to add some room around the text
            // TextBlock.text is bound to
            new go.Binding("text", "key"))

      // but use the default Link template, by not setting Diagram.linkTemplate

      // create the model data that will be represented by Nodes and Links
      myDiagram.model = new go.GraphLinksModel(
          { key: "Alpha", color: "lightblue" },
          { key: "Beta", color: "orange" },
          { key: "Gamma", color: "lightgreen" },
          { key: "Delta", color: "pink" }
          { key: -1, from: "Alpha", to: "Beta" },
          { key: -2, from: "Alpha", to: "Gamma" },
          { key: -3, from: "Beta", to: "Beta" },
          { key: -4, from: "Gamma", to: "Delta" },
          { key: -5, from: "Delta", to: "Alpha" }
      myDiagram.model.linkKeyProperty = 'key'

      myDiagram.addModelChangedListener((e) => {
        if (e.isTransactionFinished && e.model) {
          const dataChanges = e.model.toIncrementalJson(e);
          if (dataChanges !== null) {
            document.getElementById('modeldata').innerHTML = myDiagram.model.toJson();
            document.getElementById('datachanges').innerHTML = dataChanges;


When I create the following selection:


and then press ctrl+x (CUT), I get the following state and data changes:

This seems correct.

However, when I now paste my clipboard with ctrl+v (PASTE), the diagram, model and data changes look as follows:

As can be seen, the model data and the diagram are in sync (as expected). However, the datachanges seem incorrect to me. I tells that it has inserted and modified three links and also the modification data is missing from or to properties. Is this expected? Or is this a bug?


That behavior is correct. Pasting a link, by itself, is a no-op because there is no automatic connecting of any pasted links to any existing nodes.

In your case it pasted a node and three links which were connected each at one end to that newly pasted node. But because the policy is to not successfully paste a link unless both ends are connected, those links were removed again. That’s why the link keys were inserted, modified, and removed all in the same toIncrementalData results.

Thanks, I missed that the dataChanges also included that the links were removed again; makes sense. This info can be used to process the update properly.