Get modified nodes and links

Hi,

Is possible to get only the modified nodeData and/or LinkData? I want to update only this modified data in the DB

Regards,

Yes, read GoJS Events -- Northwoods Software, the section about Model Changed events. Note this part of the section:

It is commonplace to want to update a server database when a transaction has finished. Use the ChangedEvent.isTransactionFinished read-only property to detect that case.

Hi,

I have two nodes connected by a link

I tried this:

myDiagram.model.addChangedListener(function(e , obj) {
  if (!e.isTransactionFinished) return;
  for (var iter = myDiagram.selection.iterator; iter.next(); ) {
    var part = iter.value;
    if(part instanceof go.Node) {
      if(part.data.key<0) { //new nodes
        return;
      } else {  //existing nodes
        console.log(part.data.key); //the modified node
      }
    }
  }

});

but if I move any node, the link also changes. How I can get that changed link?

Regards,

Your code is looking at Diagram Nodes and Links, not Model data. But your listener is on the Model.

So you’ll want to do something like:

myDiagram.model.addChangedListener(function(evt, obj) {
  if (!evt.isTransactionFinished) return;
  var txn = evt.object;  // a Transaction
  if (txn === null) return;
  txn.changes.each(function(e) {
      // ignore Diagram ChangedEvents
      if (e.model === null) return;
      console.log(e.toString());
    });
});

You can look at each ChangedEvent and decide whether it’s a change to the model data that you care about. Of course there won’t be any model data change unless it’s structural, in which case the Diagram will make changes to the Model for you automatically, or unless you have defined a TwoWay Binding on the property so that the model data is updated automatically.

If you care about the order in which you look at the ChangedEvents, you might need to iterate over the Transaction.changes list in reverse order.

In this part

txn.changes.each(function(e) {
// ignore Diagram ChangedEvents
// if (e.model === null) return; //I want to get all the modified objects keys
console.log(e.toString());
});

How can I get the obj.data.key in loop?

Regards,

For Property changes, e.object is the data that was modified.

I’m trying to update a property of a modified nodes or links

myDiagram.nodeTemplateMap.add("activity",
    $(go.Node, "Spot", diagramNodeStyle(),

      $(go.Panel, "Auto",
        $(go.Shape, "RoundedRectangle", {
          minSize: new go.Size(70, 50),
          maxSize: new go.Size(70, 50),
          fill: NODE_FILL,
          strokeWidth: 1,
          segmentIndex: 1,
          stroke: "black"
        }
        ),
        $(go.TextBlock, "C", { //to correlative text
          margin: new go.Margin(1,0,0,0),
          isMultiline: true,
          maxSize: new go.Size(65, 10),
          font: "6pt Helvetica, Arial, sans-serif",
          textAlign: "center",
          isMultiline: true,
          alignment: go.Spot.MiddleTop,
          wrap: go.TextBlock.WrapFit,
          stroke: "#7E7B7B"
        },
        new go.Binding("text" , "text").makeTwoWay()
        ),
        $(go.TextBlock,"Nuevo Proceso", {
            //margin: new go.Margin(12,1,1,1) ,
            isMultiline: true,
            maxSize:          new go.Size(65, 44),
            font:             "6pt Helvetica, Arial, sans-serif",
            textAlign:        "center",
            isMultiline:       true,
            alignment:        go.Spot.Center,
            wrap:             go.TextBlock.WrapFit,
            stroke:           "black",
            editable:         true
          },
          new go.Binding("text").makeTwoWay()
          )
        )
    ), new go.Binding("visible","u")
);

    myDiagram.linkTemplate =
      $(go.Link,
        { routing: go.Link.AvoidsNodes, corner: 5 },
        { relinkableFrom: true, relinkableTo: true },
        $(go.Shape),
        $(go.Shape, { toArrow: "Standard" }),
        new go.Binding("visible","u")
      );

 myDiagram.model.addChangedListener(function(evt, obj) {
      var arr = {};
      if (!evt.isTransactionFinished) return;
      var txn = evt.object;  // a Transaction
      if (txn === null) return;
      txn.changes.each(function(e) {
        // ignore Diagram ChangedEvents
        //if (e.model === null) return;
        if(e.object instanceof go.Node || e.object instanceof go.Link) {
          arr[e.object.data.key]=e.object;
        }
      });
      setUpdated(arr);
    });

  function setUpdated(arr) {
    for (var key in arr) {
      var obj = arr[key];
        myDiagram.startTransaction('updated_true');
          myDiagram.model.setDataProperty(obj.data, 'u', true);
        myDiagram.commitTransaction('updated_true');
    }
  }

I have in myDiagram “undoManager.isEnabled”: true, but with setUpdated() function, the ctrl+z it doesnt work =/ (transaction problem?)

It does not make sense to try to execute a transaction in a “Transaction” ChangedEvent listener on a Model. We will improve the documentation. Maybe we should even signal an error if someone tries to call startTransaction from within a Transaction ChangedEvent listener.

It is clearly documented that you should not be conducting transactions inside loops. A single transaction should be performed in response to some user action or other event. But in this case you shouldn’t be performing any transactions at all.

Hi,

Is there another way to achieve my goal?.. for the setDataProperty I need a transaction, right?

I really don’t think you should be modifying the model or the diagram inside any Transaction ChangedEvent. If you do, there might be unintended consequences – i.e. the behavior is undefined.

And I still have no idea of what your goal really is.

with my previous code…

  1. I have 2 “activity” nodes joined by 1 link

  2. Nodes and links has a binding property: new go.Binding(“visible”,“u”), “u” means “updated/modified”

  3. If I modify a node or link: position, text, location, points, etc… (I get the modified nodes or link key with)

if(e.object instanceof go.Node || e.object instanceof go.Link) {
arr[e.object.data.key]=e.object;
}

I want to set the “u” property = true only for that node or link

  1. If I press ctrl+z (Undo), set the “u” property = false (default value) of that node or links

Say at the end of a transaction your code modifies a node (via a data binding, but the mechanism doesn’t matter for this discussion). Wouldn’t that cause the node to be modified, and thus to stop being “updated”? (I’m assuming “updated” means that the database has been informed.)

In fact, if you are always making changes at the end of every transaction, and if those changes are in their own transaction, shouldn’t that cause an infinite loop of transactions, because your code will be executed again?

I’ve noticed something in addChangedListener() …

myDiagram.model.addChangedListener(function(evt, obj) {
var arr = {};
if (!evt.isTransactionFinished) return;
var txn = evt.object; // a Transaction
if (txn === null) return;
txn.changes.each(function(e) {
// ignore Diagram ChangedEvents
//if (e.model === null) return;
if(e.object instanceof go.Node || e.object instanceof go.Link) {
console.log(e.object.data);
//arr[e.object.data.key]=e.object;
}
});
//setUpdated(arr);
});

In diagram, if I change the inner text of any “activity” node I get, by console.log, the link object and not the node object of the modified text… why?

That depends on your node template, but changing the TextBlock.text is likely to change the size of the TextBlock, which might change the size of the Panel(s) that hold it. In turn changing the size of a Node will cause connected Links to be re-routed.

Yes, you’re right, it makes sense

myDiagram.nodeTemplateMap.add(“activity”,
$(go.Node, “Spot”, diagramNodeStyle(),

  $(go.Panel, "Auto",
    $(go.Shape, "RoundedRectangle", {
      minSize: new go.Size(70, 50),
      maxSize: new go.Size(70, 50),
      fill: NODE_FILL,
      strokeWidth: 1,
      segmentIndex: 1,
      stroke: "black"
    }
    ),
    $(go.TextBlock, "C", { //to correlative text
      margin: new go.Margin(1,0,0,0),
      isMultiline: true,
      maxSize: new go.Size(65, 10),
      font: "6pt Helvetica, Arial, sans-serif",
      textAlign: "center",
      isMultiline: true,
      alignment: go.Spot.MiddleTop,
      wrap: go.TextBlock.WrapFit,
      stroke: "#7E7B7B"
    },
    new go.Binding("text" , "text").makeTwoWay()
    ),
    $(go.TextBlock,"Nuevo Proceso", {
        //margin: new go.Margin(12,1,1,1) ,
        isMultiline: true,
        maxSize:          new go.Size(65, 44),
        font:             "6pt Helvetica, Arial, sans-serif",
        textAlign:        "center",
        isMultiline:       true,
        alignment:        go.Spot.Center,
        wrap:             go.TextBlock.WrapFit,
        stroke:           "black",
        editable:         true
      },
      new go.Binding("text").makeTwoWay()
      )
    )
), new go.Binding("visible","u")

);

but, Why I cant get that node key (with modified inner-text) in addChangedListener() ??

You can always get the GraphObject.part from which you can get the Panel.data.

Sorry, but I don’t know how to apply what you say to my previous code (in first posts) to achieve my goal

I was just answering your question:

I don’t know what code you are referring to, so that’s the best that I can do.

My answer is the general way to get the Node or Link for any GraphObject. That includes Nodes and Links, in which case .part just returns itself.

Given the Part, .data gives you the data in the model, from which you can get the key or whatever properties that you like.

Hi,

My previous code is in the reply#7 of this Post :wink:

situation

  1. from an existing BIG diagram I want to do some modifications… positions, inner-texts, rotations, etc

  2. If I press the save button I get the ALL Json data with mydiagram.model.toJson()

  3. by ajax that button pass the json data to php code and ALL DATA (modified and not modified nodes and links) is updated to DB. It means a lot of transactions :confused:

my goal is:

  1. from existing BIG diagram I want to do some modifications… positions, inner-texts, rotations, etc

  2. [I need help here] with addChangedListener() (or another method) set a new property “u”=true only to the modified nodes and links in diagram, obviously if I press ctrl+z (undo) set the “u”=false on that nodes or links

  3. If I press the save button I get the ALL Json data with mydiagram.model.toJson()

  4. by ajax that button pass the json data to php code and ONLY the data with modified nodes and links (“u”=true) is updated to DB, It means less transactions :smile:

thanks,

We might be able to add functionality like this in version 1.6. Alas that won’t help you right now, but if you’re willing to wait until we’ve done the work for 1.6, I can give you the code and you can adapt the code for 1.5. Sorry I can’t give you a date on that.