Dynamically change category of an item

Hello there,

I have a panel who’s itemArray is bound to an array on some node data. This array represents ports and I want to use different templates for these ports based on their category, but I also need to be able to update this category on the fly and have the template be replaced with the appropriate one (also without loosing any existing connected links). Is there any way to do this?

Currently I tried setting itemCategoryProperty (to a function!, not a string for the property name) which works during “first draw”, but does not update once the property actually changes (as expected). I do need this to be a computed property though. Setting itemCategoryProperty to a property name works the same way (does not watch changes to this property’s value).

Any suggestions of how I can achieve this? Preferably strictly by updating a property on the data and the change propagating to the UI (so no direct calls to the Diagram). Thank you.

Yes, it is true that there is no Model.setCategoryForArrayItem method. So there’s no easy answer to your question.

FYI, the Model.setCategoryForNodeData method is called automatically by Model.set when it recognizes that data is a node data object and the property name is the same string as the Model.nodeCategoryProperty. But not for item data objects.

I’ll have to think about a solution. Part of the problem is that array items can be numbers or strings or booleans, and there can be duplicate values, so there isn’t any reasonable and reliable way for there to be properties that could be set for all array items.

I just tried this, with the assumption that all item array items are Objects, toggling between the default category (“”) and the category “G”, operating on the second node data object of the Model.nodeDataArray.

// toggle category of all items of the second node
document.getElementById("myToggleButton").addEventListener("click", e => {
  const m = myDiagram.model;
  const ndata = m.nodeDataArray[1];
  m.commit(m => {
    const a = m.cloneDeep(ndata.itemArray);
    a.forEach(d => d.category = (d.category === "G" ? "" : "G"));
    m.set(ndata, "itemArray", a);

I think this does what you want, although it does require deep copying the item array. Existing links connecting with the item panels were not removed by the data replacement.

Thank you very much for the answer, @walter!

That is actually the workaround we are using now; switched to an immutable array for the ports and we just create a new one and replace it.

But we still run into the problem with links not being redrawn when we reorder the ports (this one Swapping order of ports doesn't update links) :(. The workaround for this one works as well, but it is a bit cumbersome to implement; to keep the code clean we added a model changed listener to the diagram, watch for that ports array being changed, and calling invalidateRoute for all those links connected to those ports at the end of a transaction.

Thought there would be a better solution than two workarounds :(.

Thank you very much again! Really appreciate the clarification.