Binding reset on moving the node

Hi,

I have a binding on a vertical panel as follows:

 $(go.Panel, 'Vertical',
                {
                    row: 2, column: 1, name: 'PROPTEXT',
                    width: 205,
                    margin: new go.Margin(-1, -1.5, 0, 35)
                },
                new go.Binding('visible', '', (data) => {
                    return this.qViewVisible;
                }),

Where qViewVisible is a boolean flag that can be set by the user in a different menu.

I also have a panelExpander button to control the visibility of this panel on each node. Refer below:

$("PanelExpanderButton", "PROPTEXT",
                        {
                            row: 2, column: 2,
                            margin: new go.Margin(0, 0, 10, 0),
                            'ButtonBorder.fill': 'white', '_buttonFillOver': 'white',
                            '_buttonStrokeOver': 'white',
                            cursor: 'pointer',
                            click: (e, btn) => {
                                var diagram = btn.diagram;
                                if (diagram === null) return;
                                if (diagram.isReadOnly) return;
                                var elt = btn.findTemplateBinder();
                                if (elt === null) elt = btn.part;
                                if (elt !== null) {
                                    var pan = elt.findObject('PROPTEXT');
                                    if (pan !== null) {
                                        diagram.startTransaction('Collapse/Expand Panel');
                                        pan.visible = !pan.visible;
                                        diagram.commitTransaction('Collapse/Expand Panel');
                                    }
                                }
                                e.handled = true;
                            },
                            background: 'white'
                        },
                        go.GraphObject.make(go.Shape,
                            {
                                name: 'ButtonIcon',
                                fill: '#10069f',
                                stroke: '#10069F',
                                strokeWidth: 1,
                                width: 10,
                                height: 7,
                                background: 'white',
                            },
                            new go.Binding('geometryString', 'visible',
                                (vis) => { return vis ? 'F M24.642,18.124l-1.768,1.768L16,13.017,9.124,19.892,7.357,18.124,16,9.481Zm0,0' : 'F M24.642,13.874l-1.768-1.768L16,18.981,9.124,12.106,7.357,13.874,16,22.517Zm0,0' }
                            ).ofObject('PROPTEXT')
                        )
                    ),

Scenario:

  • I have a diagram with 4 nodes in it. PROPTEXT panels of all 4 nodes are initially not visible.
  • I click on the panelExpander button for node 3, which expands the PROPTEXT panel only for that node
  • Now i move node 3 a bit on the diagram canvas, Using the debugger tools i see that the Binding on the visible property is triggered for all the nodes on the canvas, and resets it to the value of qViewVisible. This now results in closure of the panel for node 3 just because the node was moved on the canvas

How can i prevent this behaviour? I dont want to reset the binding on the visible property just on moving the node.

By specifying the source property of a Binding to be the empty string, you are asking that binding to be evaluated whenever bindings are evaluated for that Part. Because the value of the conversion function does not depend on the state of the data object, it should not be surprising that the results are unpredictable. Imagine if the conversion function returned whether it is windy outside – the GoJS data binding system cannot be expected to evaluate such a binding only when the weather changes. It is the app’s responsibility to tell the GoJS model that some state has changed.

From the point of view of the diagram, “qViewVisible” is a global variable that is shared by all nodes. So you could use the shared Model.modelData object: new go.Binding("visible", "ViewVisible").ofModel(). Then whenever your this.qViewVisible changes, you should call diagram.model.set(diagram.model.modelData, "ViewVisible", this.qViewVisible) as part of a transaction. EDIT: I just renamed the modelData property name to make it clear that it is not the same as your this.qViewVisible property.

https://gojs.net/latest/intro/dataBinding.html#BindingToSharedModelDataSource

This is working fine except for one issue. When i drag a new node onto the diagram, it does not reflect the correct visibility. But once i change the qViewVisible, it reflects on the nodes.

I have already called diagram.model.set(diagram.model.modelData, "ViewVisible", this.qViewVisible) as part of a transaction while initializing the diagram.

What am i missing?

I am unable to reproduce any problem. I started from the sample that I gave you in Unique names on drag/drop and I made the following changes:

  • added a “VIS” property to the Model.modelData object:
"modelData": {"red":1, "green":1, "blue":0, "orange":0, "none":0, "VIS": false},
  • added a small Shape to the node template:
      . . .,
      $(go.Shape,
        { visible: false, width: 8, height: 8, alignment: go.Spot.BottomRight },
        new go.Binding("visible", "VIS").ofModel())

Now when I load the model, the nodes do not show any small black square in the bottom right corner of each node. Drag-and-dropping a node from the Palette creates a node that does not have that small square either.

Then I modify the “VIS” property of the modelData object:

myDiagram.model.commit(m => m.set(m.modelData, "VIS", true))

Now suddenly all of the nodes in the diagram have those small squares. And when I drag-and-drop a new node from the Palette, it does too.

Naturally, setting “VIS” back to false hides all of the small squares.