Get reference to parent object in model from itemArray for binding

Question: Given a model that uses a parent-child relationship in which the child objects are used to power an itemArray, is it possible to get a reference to the parent object of the model from the child in a binding function.

Scenario: Where there are many child objects and binding is being used on some property, say the fill, it might be easier and less resource intensive to set the desired fill on the parent in the model rather than each child. Therefore, in the binding function we need to be able to get to the parent to read the fill.

Example: Based on the id of a child being odd or even set its fill to the appropriate color known to its parent (cut down for readability)

nodeDataArray= {parent: {fillOdd: 'red', fillEven: 'blue', children: [ {id: 1}, {id: 2}, {id: 3} ....]}

How to use this model where the children nodes act as an itemArray and have a binding function on the itemArray template similar to:

new go.Binding("fill", "", function(data) { return (data.id % 2) === 0 ? data.parent.fillEven : data.parent.fillOdd})

Additional Node: As far as my research goes I cannot see that JavaScript provides an automatic reference to the parent of a child object from the child perspective. One can add something in code but if we have to do that we may as well add the odd/even color details to the child in the first place and then not have to worry about potential memory leaks in dodgy JS interpreters.

That is probably #1 on the list of significant missing binding features.

But yes, you could add references to the “parent” data object. There shouldn’t be any problems with memory management, but Model.toJson would not work.

Thanks Walter. I shall work around it for now.

Is there any progress on this missing feature?

Or how can I bind a value of the parent object to an itemTemplate child?

No, there isn’t. But you have always been able to get to the node data object in a converter function for a Binding on a GraphObject within an item template. That may or may not have been what @JEE did.

If the node data Array were:

[  // node data
  {
    key: 1,
    text: "Node 1",
    stroke: "orange",
    items: [
      { color: "red" },
      { color: "green" },
      { color: "blue" }
    ]
  },
  {
    key: 2,
    text: "Node 2",
    stroke: "purple",
    items: [
      { color: "orange" },
      { color: "yellow" }
    ]
  }
]

The node template could be:

$(go.Node, "Vertical",
    $(go.TextBlock, new go.Binding("text")),
    $(go.Panel, "Horizontal",
        new go.Binding("itemArray", "items"),
        {
          itemTemplate:
            $(go.Panel,
                $(go.Shape,
                    { width: 30, height: 30, fill: "white", strokeWidth: 2 },
                    new go.Binding("fill", "color"),
                    new go.Binding("stroke", "color", function(color, shape) { return shape.part.data.stroke; }))
            )
        }
    )
)

This would produce:

This clearly is not as general as having a Binding.ofParentData method which would change the binding source to be data object holding the items Array of an item, if for no other reason than that the “color” mentioned as the source property gets the “color” property on the item object, not on the Part.data object. But this work-around is good enough for most people in most cases.