Search code examples
extjsremovechildtreepanel

How to delete a node from an Ext TreePanel if the node hasn't been rendered


I've found that I can't delete nodes that haven't been rendered yet. The following code shows what I mean. I ran it from the Chrome's (and Firebug's) command line while on http://dev.sencha.com/deploy/dev/exa...dow/hello.html (since that page has ext preloaded)

I typed each statement separately to make sure there were no issues with asynchronous operations (even though the tree data is in memory)

Ext.getBody.update('');
// Tree with preloaded nodes in memory 
var tree = new Ext.tree.TreePanel({ 
   renderTo: Ext.getBody(),  
   width: 300,  
   height: 500,  
   rootVisible: false, 
   loader: new Ext.tree.TreeLoader({preloadChildren:true}), 
   root: new Ext.tree.AsyncTreeNode({ 
     expandend: true, 
     children: [ 
        {text: 'Folder 1', id: 'folder1', leaf: false, children: [ 
            {text: 'File 1', id: 'file1', leaf: true}, 
            {text: 'File 2', id: 'file2', leaf: true} 
        ]} 
     ] 
   }) 
}); 

// Try to delete 'File 1', notice that the folder has never been expanded 
tree.getRootNode().childNodes[0].childNodes[0].remove(true); 

// Expand the node and see that 'File 1' is still there 
tree.getRootNode().childNodes[0].expand(); 

// Delete the first child 1 again, it works now that it's been rendered 
tree.getRootNode().childNodes[0].childNodes[0].remove(true);

Any suggestions on what to do?

ANSWER

var nodeToRemove = tree.getRootNode().childNodes[0].childNodes[0];
if (!nodeToRemove.rendered) {
    var children = node.parentNode.attributes.children;
    Ext.each(children, function(child, index){
        if (child.id == nodeToRemove.id) {
            chilren.splice(index, 1);
            return false;
        }
    }) ;
} else {
    nodeToRemove.remove(true);
}

Solution

  • I finally figured it out, actually Condor from Ext-JS support figured it out for me.

    The problem was that by default, a TreeLoader clears its children when TreeLoader#reload is called (it's called by AsyncTreeNode#expand(), if the clearOnLoad option is true (default).

     (TreeLoader) load : function(node, callback, scope){
            if(this.clearOnLoad){
                while(node.firstChild){
                    node.removeChild(node.firstChild);
                }
            }
            if(this.doPreload(node)){ // preloaded json children
                this.runCallback(callback, scope || node, [node]);
            }
    

    So creating my tree loader with clearOnLoad: false fixes my problem. Except when I remove all the child nodes. To fix that I needed the following patch:

    Ext.tree.TreeLoader.prototype.doPreload = 
    Ext.tree.TreeLoader.prototype.doPreload.createSequence(
      function(node){
        if (node.attributes.children)  {
          node.attributes.children = [];    
        }
      }
    );
    

    Here's a link to the ext-js thread:

    http://www.sencha.com/forum/showthread.php?122681-Deleting-unrendered-nodes-from-a-tree-doesn-t-work&p=567459#post567459

    @Pumbaa: This is a solution, rather than a workaround as you suggested, but I'm really thankful for your help.