Binding Does not Evaluate on Initial Load of Diagram

I have created a context menu with a delete button as follows:

$ < go.Panel > (
	'ContextMenuButton', {
		'ButtonBorder.fill': '#F1F1F1'
	}, {
		click: (e, obj) => {
			const ad = obj.part as go.Adornment;
			const node = ad.adornedPart as go.Node;
			this.commentNode = node;
			this.commentDeleted.emit(node);
		}
	},
	new go.Binding('ButtonBorder.fill', '', () => {
		const commentAct = this.commentNode.data as Activity;
		console.log(
			'Delete comment button binding: ' +
			commentAct.comments
		);
		return commentAct && commentAct.comments && commentAct.comments !== '' ?
			'#F1F1F1' :
			'transparent';
	}),
	$(
		go.TextBlock,
		'Delete', {
			font: this.defaultFont,
			desiredSize: new go.Size(50, 25),
			alignmentFocus: go.Spot.Center,
			margin: new go.Margin(10, 0, 0, 18)
		},
		new go.Binding('stroke', '', () => {
			const commentAct = this.commentNode.data as Activity;
			console.log(
				'Delete button stroke binding: ' +
				commentAct.comments
			);
			return commentAct && commentAct.comments && commentAct.comments !== '' ?
				'black' :
				'lightgrey';
		})
	)
),

On initial load of diagram, when I opened the context menu for the first time, I did not even see the console.log() statements printing to the console.

Needless to say, commentAct.comments should be empty on initial load, I expected the delete button to be transparent with lightgrey stroke, but I saw #F1F1F1 background color and black stroke.

Once I set commentAct.comments to a non-empty string, then reset commentAct.comments to the empty string, then the Binding correctly sets the background color to transparent and the stroke to lightgrey.

Can you please advise on the reason and the fix?

Thanks.

First, you seem to have the cast to <go.Panel> in the wrong place.

Second, how can you be sure that this.commentNode is a Node? I’m guessing that’s causing the error before the console.log can happen.

Third, if I understand your code, wouldn’t this binding be much simpler?

    new go.Binding("ButtonBorder.fill", "comments", c => c ? "#F1F1F1" : "transparent")

and this:

    new go.Binding("stroke", "comments", c => c ? "black" : "lightgray")

Thanks Walter for the quick reply.

this.commentNode is declared as follows so it is a go.Node:

commentNode: go.Node;

What did you mean by the following?

Never mind about the cast – must be a problem with formatting in this forum.

I’ve added a Third point about simplifying your Bindings, making them more efficient and easier to read (if I understand your code’s intent correctly).

Yes that was the intent of my code.
I wrote the expanded version of the Binding so that I can use console.log().

I tried switching to your simplified version; but the Binding is still not evaluated on initial load.

Anything else that you would like to know to help diagnose the problem?
Any suggestions on what can cause the problem?

I’m still not sure what effects you want to achieve – there are so many combinations of possibilities.

And part of the confusion is that unlike Nodes, which are copied for each node data object in the model, context menus (and tooltips) are singletons and are shared by all nodes that have a reference via GraphObject.contextMenu (or GraphObject.toolTip). So if you make a change to one of them, for example through a Binding, then that change will remain for all uses of that context menu until it is set again.

Furthermore, remember that Bindings are not evaluated if the source is undefined.

So if you want the first context menu button of a context menu to look red only for nodes that have a particular property set on the data, but to look normal for other nodes, you could do something like:

      $(go.Node, . . .,
        {
          contextClick: function(e, node) {
            // this resets the first button to have the normal appearance
            node.contextMenu.elt(0).setProperties({ "_buttonFillNormal": "#F5F5F5", "ButtonBorder.fill": "#F5F5F5" });
          },
          contextMenu:
            $("ContextMenu",
              $("ContextMenuButton",
                $(go.TextBlock, "Special button"),
                // these bindings change the color of the button if the data.special property exists and is truthy
                new go.Binding("_buttonFillNormal", "special", c => c ? "red" : "yellow"),
                new go.Binding("ButtonBorder.fill", "special", c => c ? "red" : "yellow"),
              ),
              $("ContextMenuButton",
                $(go.TextBlock, "Normal button")
              )
            )
        },
        . . .