Expand/Collapse creating orphaned nodes

i’ve been working on implementing the expand/collapse button w/in my tree.
the diagram has some filters to change the color of the nodes, but i would like to keep the expanded/collapsed intact when doing a post back. to do this i added the “everExpanded” value to the model, and update this when a node is expanded (true) or collapsed (false).

the problem that i’m running into is, sometimes not all node are being hidden when they should be collapsed and sometimes i end up w/ orphaned nodes.

see example photo:

the nodes that are yellow should be expanded while the dark green should be collapsed.

below are some snippits of my code.

template:
myDiagram.nodeTemplate =
$(go.Node, “Spot”,
{ selectionObjectName: “PANEL”, isTreeExpanded: false }, //panel for expand/collapse selector
new go.Binding(“isTreeExpanded”,“everExpanded”),…
expander button:
$(“TreeExpanderButton”, {
alignment: go.Spot.Bottom, alignmentFocus: go.Spot.Top,
click: function(e,obj){
var node = obj.part;
if (node === null) return;
e.handled = true;
var data = node.data;
var model = myDiagram.model;
myDiagram.startTransaction(“updateEverExpanded”);
if(data.everExpanded === “false”){
model.setDataProperty(data, “everExpanded”, “true”);
var children = node.findTreeChildrenNodes;
if(children.count === 0){
obj.visible = false;
}
}
node.isTreeExpanded = !node.isTreeExpanded;
myDiagram.commitTransaction(“updateEverExpanded”);
save();
}
})

at end of init() to handle expanding/collapsing:

var nodes = myDiagram.findTreeRoots();
var nodes2 = myDiagram.nodes;
var nodes3 = myDiagram.nodes;

myDiagram.startTransaction("rootExpand"); //expand the root parents
    while (nodes.next()){
        var node = nodes.value;
        node.expandTree(1);
    }
myDiagram.commitTransaction("rootExpand");

myDiagram.startTransaction("expandCollapse"); //expand nodes that are expanded
while(nodes2.next()){
    var node = nodes2.value;
    var keyID = node.data.key; //get the keyID for the node
    var data = myDiagram.model.findNodeDataForKey(keyID); //get the data for the node
    if(data.everExpanded === "true"){
        node.expandTree(1);            
    }
}        
myDiagram.commitTransaction("expandCollapse");

myDiagram.startTransaction("collapseNodes"); //collapse nodes that are collapsed
while(nodes3.next()){
    var node = nodes3.value;
    var keyID = node.data.key; //get the keyID for the node
    var data = myDiagram.model.findNodeDataForKey(keyID); //get the data for the node
    if(data.everExpanded === "true"){
        node.collapseTree(2);            
    }
}        
myDiagram.commitTransaction("collapseNodes");

Do you need to dynamically decide whether or not there are any children for a particular node when the user tries to expand it?

If not, you should change your Binding(“isTreeExpanded”, “expanded”).makeTwoWay().
[Note that I have changed the data property name to be more descriptive.]
Then you can get rid of your click event handler and all of the code that you have at the end of your init() function.

I don’t need to dynamically decide if there are children or not, the entire structure is loaded and nothing changes based on children or not.
the main goal was to be able to post back, modify data but not structure (parent child relationship) and keep the same expanded/collapsed state.

i was able to get the desired result by changing the if statement in the click event to:
if(data.everExpanded === “false”){
model.setDataProperty(data, “everExpanded”, “true”);
var children = node.findTreeChildrenNodes;
if(children.count === 0){
obj.visible = false;
}
}else{
model.setDataProperty(data, “everExpanded”, “false”);
}

but if i’m following what you said, i could use the “short form” standard expand/collapse button, remove all pieces of code at the end of init() and set twoway binding on expanded and this will inherently modify the model data of the expand/collapse AND keep the expand/collapse state?

Yes, that’s the magic of TwoWay data binding.

$(go.Node, . . ., new go.Binding("isTreeExpanded").makeTwoWay(), . . .
Or if you want to specify your own data property name:

$(go.Node, . . ., new go.Binding("isTreeExpanded", "expanded").makeTwoWay(), . . .