setCategoryForNodeData does not apply custom underscore-prefixed properties from the new template

Hello,

I’m using Model.setCategoryForNodeData to switch a node between templates at runtime. The target template defines custom underscore-prefixed properties (e.g. _detailedFlag, _shouldResize) on the Node, but the source template does not have them.

After calling setCategoryForNodeData, the Part is visually rebuilt with the correct template (shape, text, etc.), but the custom _ properties from the new template are not present on the rebuilt Part. They remain undefined.

Minimal reproduction:

Change category (placeholder → detailed)

   <script>
     const $ = go.GraphObject.make;
     const log = (msg) => {
       document.getElementById('log').textContent += msg + '\n';
       console.log(msg);
     };

     const diagram = $(go.Diagram, 'myDiagramDiv', {
       'undoManager.isEnabled': true,
     });

     // "placeholder" template — no _ properties
     const placeholderTemplate = $(go.Node, 'Auto',
       $(go.Shape, 'Rectangle', { fill: '#eee', stroke: '#999' }),
       $(go.TextBlock, { margin: 8 }, new go.Binding('text', 'name'))
     );

     // "detailed" template — has _detailedFlag and _shouldResize
     const detailedTemplate = $(go.Node, 'Auto',
       { _detailedFlag: true, _shouldResize: true },
       $(go.Shape, 'RoundedRectangle', { fill: 'lightcoral' }),
       $(go.TextBlock, { margin: 8, font: 'bold 14px sans-serif' },
         new go.Binding('text', 'name'))
     );

     diagram.nodeTemplateMap.add('placeholder', placeholderTemplate);
     diagram.nodeTemplateMap.add('detailed', detailedTemplate);

     diagram.model = new go.GraphLinksModel([
       { key: 1, name: 'Node A', category: 'placeholder' },
     ]);

     function logNodeState(label) {
       const node = diagram.findNodeForKey(1);
       if (!node) {
         log(label + ' — node not found');
         return;
       }
       log(label);
       log('  data.category: ' + node.data.category);
       log('  node._detailedFlag: ' + node._detailedFlag);
       log('  node._shouldResize: ' + node._shouldResize);
     }

     logNodeState('INITIAL STATE (placeholder — no _ props)');

     document.getElementById('changeBtn').addEventListener('click', () => {
       const node = diagram.findNodeForKey(1);
       if (!node) return;

       diagram.startTransaction('changeCategory');
       diagram.model.setCategoryForNodeData(node.data, 'detailed');
       diagram.commitTransaction('changeCategory');

       logNodeState('AFTER setCategoryForNodeData → detailed');
     });
   </script>
 </body>
 </html>

Expected behavior:
After setCategoryForNodeData(node.data, ‘detailed’), the rebuilt Part should have _detailedFlag: true and _shouldResize: true as defined in the detailed template.

Actual behavior:
Both node._detailedFlag and node._shouldResize are undefined on the rebuilt Part.

Question:
Is this expected? Is there a recommended way to ensure custom _ properties from the new template are applied when switching categories? Currently my workaround would be to manually insrert properties with " _ " when changing categories.

No, that’s a bug. You’ll note that attached properties (i.e. properties that aren’t defined by the class but are set on the instance and whose names start with “_”) are correctly copied on all of the GraphObjects that are copied from the new node template. The bug is that we’re not doing that on the Part (a Node in your case). I believe this is fixed in 3.1.7, which we will release soon.

Thanks for reporting the bug.

1 Like