Generate nodeTemplate dynamically


I am currently working on a project that has a huge focus on generating GoJS diagrams dynamically.

Everything I saw (so far) in samples was based on a staticly defined nodeTemplate or on several templates (nodeTemplateMap - but still static).

I already implemented a way to create dynamic linkTemplates based on the following structure:
→ My component receives an array like this:

→ Based on that I create a linkTemplate for each item in the array with the following template:

→ That way I was also able to create a linkTemplate Editor that lets me create linkTemplates and append them to the linkTemplates JSON array and my dynamic linkTemplates work.

But that only works because I could create such a generic skeleton of a link template that I can fill with different values.
The requirements for nodeTemplates are a bit higher, so I want to be able to create elements with various panels, settings and all, which does not really fit into one generic structure.

Is there a way to still achieve that? Is it for example possible to add conditionals or loops into the structure? Or is it possible to create a node template gradually by appending the template if necessary?

Best regards
Jonas Czeslik

In the case of links, it seems to me that you could get away with a single Link template that had a bunch of Bindings.

Yes, nodes can typically be more varied than links can. But I don’t know how to help you if you do not somehow express the range of variation that you want to support.

Also, what do “conditionals or loops” have to do with the node or link templates? That seems more of a layout/routing kind of responsibility, unless I am misunderstanding of what you want.

My nodeTemplate should be able to cover single panels but also compositions of those panels, so it should be able to generically fill a template for such a basic node:

But it should also be able to fill a template for those composed nodes:

That’s why I had the association with loops because if one could append such a nodeTemplate with basic panels according to the necessary amount, it would again be possible to also create those templates dynamically.

So, something like

myDiagram.nodeTemplate = {Insert template for super node that contains everything within};
for each subpart:
myDiagram.nodeTemplate.append({Insert template part for subpart})

I know, these functions don’t exist, but I was hoping that this general idea would be accomplishable anyhow.

Could you please tell us how many kinds of variation there might be in the how the nodes are arranged internally? Is the data needed to define such nodes going to be available as descriptor objects in an Array that the node data object has?

The requirement at the end is that a user can define himself such a node structure in a UI configurator (so something like in the Planogram sample). That way he can put together a composed node based on basic nodes that he can style differently.
Since the software should be able to address all kinds of customers with completely different node structures, such a dynamic way is necessary, so without having to write out a lot of different nodeTemplates for each customer, one could easily configure such a nodeTemplate with a simple UI, save necessary information to rebuild this structure in a JSON and in my diagram component I could iterate through these nodeTemplates coming from the JSON and generate the nodeTemplates dynamically.

So - the same concept like in my linkTemplate configurator, which looks like this (at the moment its still pretty basic and does not have a lot of setting options, but its easily expandable):


The user can play around with the settings and create their own template with direct feedback how the links look like.
After applying it adds a new link template to the linkTemplateMap based on the chosen values and with the chosen name as category. Also it saves the necessary values to rebuild that template in a file, so the component can add the template on next initialization again.

I hope, the goal got clear. Basically its three steps:

  • providing something like a planogram
  • extracting necessary information from such a node put together by the user in the planogram
  • using that information to add a nodeTemplate that reflects that node

The only reason for having a template is so that the app can change the design of the node without consideration of the node data properties. Bindings provide parameterization based on the node data properties, when desired.

So, how do you want to organize your data? Will each node have all of the information needed to configure that (perhaps unique) node? If so, one general node template should suffice, although it could be quite complicated. If not, then you would want to share a lot of the details for each type of node, probably in the shared Model.modelData object, so that at load time you can dynamically construct a different node template for each type of node before assigning the Model.nodeDataArray.

I dont know, if I am understanding you correctly, but I dont want a unique nodeTemplate for each node.
I want to have a unique nodeTemplate for each type of node. For one diagram that can mean that I only have one nodeTemplate, which all nodes are reflected by and for another diagram there can be for example more than one type or also one but a completely different one. And this type of node should be definable by the user.

That way he would also define something like "The second sub node (panel) in the third row should bind its text property to ‘fillLevel’ ". And then I have a config, where my concrete nodes and their data are stored, which then of course saves this concrete fillLevel parameter. My diagram component receives this config that on the one hand has something like nodeTemplates: {…}, which lets me dynamically create fitting nodeTemplates based on some key value pairs and on the other hand has something like nodes: {…}, where the data for concrete nodes are stored. So my component firstly creates all the nodeTemplates dynamically and then creates the nodeDataArray based on the concrete nodes.

That way I dont only make nodes dynamically filled with data but also nodeTemplates be dynamically filled with nodeTemplate structuring data. So, customer A can create himself a monitoring system for his sensors, whose 5 most important properties are visible in 5 different sub nodes and customer B can create a completely different diagram where his nodes only have to include 3 different sub parts, but with other bindings.

I dont see another way to dynamically be able to react on customer {1, … n} with their (potentially) respective node structures {1, … n} without having to staticly and time-consumingly provide n different node templates.

Yes, that is the second option that I outlined. So I suggest that you put all of that configuration information in the shared Model.modelData object, so that the information is written/read with the model and so that it remains even if all of the nodes are deleted.

And when loading a model you will have a pre-processing step where you construct all of the node templates and link templates. You’ll make sure that the data in the Model.nodeDataArray and GraphLinksModel.linkDataArray have the appropriate category to name the newly defined template. Finally you can assign Diagram.model.

I dont think that this is the step that causes the problems for me. To transfer and store that could possibly build a nodeTemplate is doable.

And when loading a model you will have a pre-processing step where you construct all of the node templates and link templates.

That is the main point. How do I construct a node template programmingly and generically without having to write it out in person?
Lets say I have two JSON objects for two nodeTemplates that I want to construct in the component initialization. Like discussed earlier, those nodeTemplates should be composable of one or more panels and each panel (sub part) has exactly two options (to make it simple) to modify it. You can bind a color and a text on these sub parts.

The first one is like:
EDIT: Here the JSON better formatted:

And the second one is a completely basic node that is not composed by sub parts:
EDIT: Here the JSON better formatted:

The nodeTemplates I want to generate with these information should be pretty clear, but I still dont know how to transform these information into two different nodeTemplates without having to write them down explicitly.

OK, so you show two template definitions. It seems to me they are missing the template name that could be used as the data.category. Is that correct?

And what would a simple Model.nodeDataArray look like?

Regarding your basic question: remember that templates are defined as JavaScript. At least one sample demonstrates constructing templates dynamically: Data Flow Diagram

Thats what I was searching for!
I am now trying to do the following approach:

So, for each nodeTemplate from the config I am defining a general position based node with all its basic functionalities (later something like selectable, resizable and other stuff will be coming from the config as well).
And in each nodeTemplate definition there is a number of subnodes that are appended as a panel to the basic node, so I can fill a variety of sub panels into the main node.

So, something like

and a concrete definition of such a node (dont need to post it here) will be causing such an item on the map: