Generating data bound node "on the fly" / dynamic nodeTemplate

Hi,
have you ever thought about extending the signature for the nodeTemplate property in Diagram in this way?

nodeTemplate: Part | (nodedata: ObjectData) => Part

That would help me a lot.
Our data model for nodes is very complex and varied, and is optimized for specific requirements. For example, we completely avoid arrays. With the capabilities GoJS offers so far, it is not possible for me to create a template that fits the data model. Depending on the specific node data we have to build the Node and also the data binding (i.e. set Panel.data for some subpanel to a specific object in the nodedata).
Currently we only use a very simple default template for our nodes and complement the nodes with additional elements and data binding after their automatic creation.
This seems to work so far, but it is difficult to handle all situations where a node is automatically generated
Thanks a lot

What would be the responsibility of that function? How/when/why would it be called?

Are you not able to use different templates for different situations?

This function should be called every time when the default nodeTemplate (from nodeTemplateMap) is read/accessed in order to generate a node for a given nodedata.
Or in general terms: Instead of generating a Node from a static template (a go.Part) and the nodedata this function should be called with the actual nodedata as a parameter to generate the Node for that nodedata.

No, I can’t use different templates, because I have no reference to the nodedata while declaring a node template. And I have to set Panel.data for some subpanel to a specific object in the nodedata myself.

Well, I was really asking whether each Node is structurally very different from each other. The whole point of having multiple templates is to simplify each template for each kind of node that you want to render. Bindings are used for customizing properties to the data.

Do you still want to use data Bindings?

Yes of course I need data binding.
My nodedata (ObjectData) ist quite complex and nested and does not contain arrays. Hence I cannot go with standard go.Binding like go.Binding(“itemArray”, “some array property of nodedata”) because I have no array.
What I do is something like this (very simplified example):

for (const key in nodedata.inputs) {
const portdata = nodedata.inputs[key];
const panel = $(go.Panel,

new go.Binding(“fill”, “isConnected”), someConverter)

panel.data = portdata;
node.add(panel);

Note that the nodedata (model data) is also “bound” to a property grid and can be displayed or manipulated by it.

Do you want to have a single Panel that holds a sequence of Panels, each corresponding to a piece of data taken from within various nested properties of a non-Array Object? If so, could you have a Binding to Panel.itemArray of your data and use a converter to gather those Objects into an Array?

In the above example (which is only a simplified and small aspect of the problem), this would work in a pinch. But even then I would have to provide an itemTemplate with a lot of unnecessary data bindings. If I had access to the nodedata when creating the template (the Node), I could keep the template (the Node) much simpler and also reduce the number of data bindings to the only necessary. Our nodes can be very complex and I worry about performance and maintainability.

I’m not sure what advice to give you. The template mechanism was designed so that it was relatively efficient – instantiating a node is just copying the chosen template and setting its data, but data binding only works under specific circumstances.

Here’s a sample using a Part that isn’t copied from a template but does use data binding: Unmodeled Data But note that the data is not in the model, so the Part is not automatically created by the diagram.

This is what I expect from the function (nodedata: ObjectData) => Part
Instead of copying the template, the node is build up (incl. data binding) and returned by this function. The function is also responsible for setting its data: setting root-Panel.data to nodedata and also some child-Panel.data to some nested object in nodedata if needed.

Internally there is a PartManager class that is responsible for “managing” Parts in a Diagram based on the Model. One could just override the method that is responsible for creating Parts in a Diagram. But not only is that class not documented, its API is not at all exported, so you won’t find it in go.d.ts.

So I’m sorry, but I don’t think the kind of feature that you are looking for exists in GoJS right now.

I have assumed that this feature does not exist in GoJS. That’s why I had suggested the extension with the function. The solution you suggest would perhaps be even more flexible. Is it imaginable that the mentioned API will be exported in an upcoming version of GoJS? That I would appreciate very much.

At the moment, I’m making do as follows and I’d appreciate it if you could comment briefly on the approach.
Currently we just use a very simple default template for our nodes and add additional elements and data binding to the nodes after they are automatically created.
For this I wrote a function: complementNode(node: Part, data: ObjectData).
I call this function when initializing the diagram after setting the model. Additionally, I call this function in the diagram’s “ModelChanged” listener when a new node is inserted.

   if (e.isTransactionFinished) {
      const changes = myDiagram.model.toIncrementalData(e);
      if (changes?.insertedNodeKeys) {
          for (const key of changes.insertedNodeKeys) {
             complementNode(myDiagram.findNodeForKey(key), myDiagram.model.findNodeDataForKey(key));
          }
      }
   }
}

At first glance, this seems to work. Do you see any problems with this approach?

Well, if it’s working reliably and efficiently for you, that’s good.

However, that code does not seem to handle the cases where the data of existing nodes has been modified. Do you have separate code for that that you are not showing us, or does such a situation not happen in your app?

Thanks a lot!
Cases where the data of existing nodes has been changed are handled by the data binding I declared in my default nodeTemplate and by the complementNode function.

In addition, there may still be cases where the node needs to be patched afterwards, e.g. adding or removing some parts.

What is about my first question?

At this time there are no plans for that to be documented. It’s rather complicated, so it’s not so easily explained.

So also no chance for that extension?

At this time I don’t think so. It’s a delicate balance making new features available versus keeping the API as simple as possible. Since you are the first person to ask for this feature in the 10 year public history of GoJS, and since implementing a work-around is plausible (not just possible), I’m confident that it is best achieved by overriding methods, even though overriding methods is something we are trying to avoid requiring for most apps and although in this case it’s not easy to implement a work-around.

In the long run I do want to make PartManager public, particularly since that might help for optimizations including virtualization, but for the forseeable future there are more important features for us to make available.