How to update modelData while dragging

Hi @walter , In our requirement we are trying to update a modelData property draggingInProgress of main diagram in doActivate and doDeactivate of DraggingTool. Below is how we are doing it.

diagram.model.commit(m => {
	m.setDataProperty(
		diagram.model.modelData,
		'draggingInProgress',
		true,
	);
}, 'Set draggingInProgress')

We are putting true on doActivate and false in doDeactivate and we have dynamic bindings based on this modelData property.
When we try to do this, the bindings get the updated value on doActivate but in the doDeactivate, the diagram.model.modelData.draggingInProgress stays false and does not fire any binding updates.

If the below line is added in doActivate after the diagram commit it works fine.
diagram.model.modelData.draggingInProgress = true;

Please help in understanding why this is happening and is there any better way of doing this.

DraggingTool.doActivate calls Tool.startTransaction, and DraggingTool.doDeactivate calls Tool.stopTransaction. As long as you are trying to call Model.set on a data property between those two calls, a transaction is already ongoing, so you do not have to call commit.

Did you define your method overrides in the normal after-DraggingTool.doActivate-and-before-DraggingTool.doDeactivate fashion?

doActivate() {
  super.doActivate();
  // do any additional setup
  this.diagram.model.set(this.diagram.model.modelData, "draggingInProgress", true);
}

doDeactivate() {
  // do any additional cleanup
  this.diagram.model.set(this.diagram.model.modelData, "draggingInProgress", false);
  super.doDeactivate();
}

Hi Walter,

Thanks for the earlier reply. The suggested approach doesn’t seem to work in our scenario. Since doActivate() and doDeactivate() occur within the same transaction, does the dynamic binding on draggingInProgress get triggered twice—once when it becomes true and again when it returns to false?

To reiterate our use case:
We have a GraphObject inside our node whose visibility is controlled by a model property. We set up a dynamic binding on its visible property based on the draggingInProgress model property.

Our requirement is that the moment dragging starts, this GraphObject should become visible, and as soon as dragging stops, it should become hidden again.

Is there a recommended way to achieve this behavior?

I just tried it, and everything seems to work well. How is your app different?

[EDIT] I just noticed that changing dragging modes, from moving to copying or vice-versa, causes the state to be rolled-back, which in this case also hides the triangular shape whose visibility is controlled by the “draggingInProgress” modelData property. So I changed the code so that the setting of “draggingInProgress property is not recorded by the UndoManager. One way of doing that is by explicitly setting skipsUndoManager to true and then to false each time. An easier way is to call commit with a second argument that is null.

<!DOCTYPE html>
<html>
<head>
  <title>Minimal GoJS Sample</title>
  <!-- Copyright 1998-2025 by Northwoods Software Corporation. -->
</head>
<body>
  <div id="myDiagramDiv" style="border: solid 1px black; width:100%; height:400px"></div>

  <script src="https://cdn.jsdelivr.net/npm/gojs/release/go-debug.js"></script>
  <script id="code">
class CustomDraggingTool extends go.DraggingTool {
  constructor(init) {
    super();
    if (init) Object.assign(this, init);
  }

  doActivate() {
    super.doActivate();
    // do any additional setup with skipsUndoManager temporarily true
    this.diagram.model.commit(m => m.set(m.modelData, "draggingInProgress", true), null);
  }

  doDeactivate() {
    // do any additional cleanup with skipsUndoManager temporarily true
    this.diagram.model.commit(m => m.set(m.modelData, "draggingInProgress", false), null);
    super.doDeactivate();
  }
}

const myDiagram =
  new go.Diagram("myDiagramDiv", {
      layout: new go.TreeLayout(),
      draggingTool: new CustomDraggingTool(),
      "undoManager.isEnabled": true
    });

myDiagram.nodeTemplate =
  new go.Node("Spot", {
      // don't invalidate the layout when nodes change size because node decorations become visible or not
      layoutConditions: go.LayoutConditions.Standard & ~go.LayoutConditions.NodeSized
    })
    .add(
      new go.Panel("Auto")
        .add(
          new go.Shape({ fill: "white" })
            .bind("fill", "color"),
          new go.TextBlock({ margin: 8 })
            .bind("text")
        ),
      new go.Shape("TriangleDown", {
          alignment: go.Spot.TopRight, alignmentFocus: go.Spot.TopRight,
          width: 8, height: 12, fill: "yellow",
          visible: false
        })
        .bindModel("visible", "draggingInProgress")
    );

myDiagram.model = new go.GraphLinksModel({
  modelData: { draggingInProgress: false },
  nodeDataArray: [
    { key: 1, text: "Alpha", color: "lightblue" },
    { key: 2, text: "Beta", color: "orange" },
    { key: 3, text: "Gamma", color: "lightgreen" },
    { key: 4, text: "Delta", color: "pink" }
  ],
  linkDataArray: [
    { from: 1, to: 2 },
    { from: 1, to: 3 },
    { from: 3, to: 4 }
  ]
});
  </script>
</body>
</html>

Hi @walter ,We are doing this in the doActivate and doDeactivate as a initializing options rather than a draggingTool extension. does that change its behaviour?

The u suggested is causing the same issue i initially reported. its updating the bindings but the value stays as false and so when we release on doDeactivate the value is shown as false instead of true.

You are talking about modifying DraggingTool behavior, so overriding the doActivate and doDeactivate methods of the ToolManager.draggingTool is necessary.

If you try the sample code I just gave you without any modifications, does it behave in the manner that you want? If not, how not? If so, I don’t understand what behavior you are getting in your app and how it is different from what you want.