mergeNodeDataArray with group node causes exception

Hi!

I’m experincing troubles when trying to use mergeNodeDataArray on model whne adding group nodes. I’m getting:
GraphLinksModel.setDataProperty: property name must not be the nodeIsGroupProperty: isGroup
I tried to figure out how nodeIsGroupProperty could effort me, but i’m not sure i got the idea.
I have the next flow of data mutation:
model.nodeDataArray keeps regular nodes,
one node is getting removed from nodeDataArray its data converted to group by adding {isGroup: true} and then added to tempArray,
group nodes (completely new to model) are generated with {group: %parentKey%} parameter and added to tempArray.
rest of the nodeDataArray added to temp array.
After that i’m calling mergeNodeDataArray with tempArray as arg and getting this exception.

Assist needed.

First, I should say that one cannot dynamically change a node from Node to Group or vice-versa, nor to or from custom subclasses thereof. Trying to set the “isGroup” property in your GraphLinksModel is causing that error.

I suggest that you create a new node data object for the new group that you want to add, and that you make sure you do not use an existing key value for it. In other words, don’t set the “key” (or whatever property name you are using, Model.nodeKeyProperty) or set it to a new key value.

Hi Walter!

Actually i’m creating new node data with isGroup: true, (although it keeps node key) and adding it into model only after I removed previouse node from model, i’m doing it inside of separete transactions, so i assumed that after I removed node by a key, i can add new group node with same key since its remains unique for a model.
I kept the key of node because i need to save all the links related to previouse node for new group node.

Does it work reusing the old key if you execute two different merge… actions in two separate transactions?

Merging new group node without removing previous one, keeps old node in previous state.
Which I believe is expected behaviour

I meant one transaction to remove the node and then another one to add the group, both with the same key.

That causes all sort of side-effects. All links vanish and position of nodes is broken.

I figured I should try what I suggested. I did so with two separate approaches: the traditional modification of the data as well as the immutable data approach that calls Model.merge…. I have appended my code that tested both approaches, which each seem to work as I expected.

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2021 by Northwoods Software Corporation. -->
  <script src="https://unpkg.com/gojs"></script>
  <script id="code">
  function init() {
    var $ = go.GraphObject.make;

    myDiagram =
      $(go.Diagram, "myDiagramDiv",
        {
          "undoManager.isEnabled": true,
          "ModelChanged": function(e) {     // just for demonstration purposes,
            if (e.isTransactionFinished) {  // show the model data in the page's TextArea
              document.getElementById("mySavedModel").textContent = e.model.toJson();
            }
          }
        });

    myDiagram.nodeTemplate =
      $(go.Node, "Auto",
        $(go.Shape,
          { fill: "white", portId: "", fromLinkable: true, toLinkable: true, cursor: "pointer" },
          new go.Binding("fill", "color")),
        $(go.TextBlock,
          { margin: 8, editable: true },
          new go.Binding("text").makeTwoWay())
      );

    myDiagram.model = new go.GraphLinksModel(
    [
      { key: 1, text: "Alpha", color: "lightblue" },
      { key: 2, text: "Beta", color: "orange" },
      { key: 3, text: "Gamma", color: "lightgreen" },
      { key: 4, text: "Delta", color: "pink" }
    ],
    [
      { from: 1, to: 2 },
      { from: 1, to: 3 },
      { from: 2, to: 2 },
      { from: 3, to: 4 },
      { from: 4, to: 1 }
    ]);
  }

  // by modifying the data
  function test() {
    myDiagram.model.commit(m => {
      m.removeNodeData(m.findNodeDataForKey(2));
    });
  }
  function test2() {
    myDiagram.model.commit(m => {
      m.addNodeData({ key: 2, isGroup: true, text: "Omega", color: "green" });
      m.setGroupKeyForNodeData(m.findNodeDataForKey(3), 2);
      m.setGroupKeyForNodeData(m.findNodeDataForKey(4), 2);
    });
  }

  // using merge (i.e. immutable data)
  function testm() {
    myDiagram.model.commit(m => {
      const a = m.nodeDataArray.slice();
      a.splice(a.indexOf(m.findNodeDataForKey(2)), 1);
      m.mergeNodeDataArray(a);
    });
  }
  function testm2() {
    myDiagram.model.commit(m => {
      // assume immutable data, so copy the whole nodeDataArray
      const a = m.nodeDataArray.slice();
      a.push({ key: 2, isGroup: true, text: "Omega", color: "green" });
      // and copy any nodes that need to belong to the new group
      const o3 = m.findNodeDataForKey(3);
      const n3 = Object.assign({ group: 2 }, o3);
      a[a.indexOf(o3)] = n3;  // including replacing the reference in the new Array
      const o4 = m.findNodeDataForKey(4);
      const n4 = Object.assign({ group: 2 }, o4);
      a[a.indexOf(o4)] = n4;
      m.mergeNodeDataArray(a);
    });
  }
  </script>
</head>
<body onload="init()">
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:600px"></div>
  <!--<button onclick="test()">Test Modify</button>
  <button onclick="test2()">Test Modify 2</button>-->
  <button onclick="testm()">Test Merge</button>
  <button onclick="testm2()">Test Merge 2</button>
  <textarea id="mySavedModel" style="width:100%;height:250px"></textarea>
</body>
</html>

Hi Walter!

I tried to apply your example in one scenario and it seems to be working just fine.
Thanks a lot for assist.
I will apply this approach elsewhere i need to update model and if there anything else pop up I will continue in this thread.

Vlad.