2014-05-23 122 views
3

我正在寻找一种递归扩展树节点的方式。树没有被装载到最大。我们一次只加载一个深度级别。因此,例如,如果我的路径有3个深度级别(/ nodeId1/nodeId14/nodeId142),我想加载第一个节点,然后通过我路径中的第二个ID(在这种情况下为nodeId14)将第2级节点展开,然后得到第三等ExtJS递归扩展树节点

然而,当一个节点展开时,代理有一个AJAX调用来获取节点的孩子的数据,并且由于这个调用是异步的,程序本身试图向前移动下一级节点,在请求有时间完成之前给我一个“节点未定义错误”,因为级别2尚未加载。

我一直在寻找1天现在如何解决这个问题,但没有任何帮助。我发现了一个解决同样问题的博客,但帖子是从2009年开始的,他使用的一些东西已经过时。

http://hamisageek.blogspot.gr/2009/04/extjs-tip-recusively-opening-nodes-in.html

一些代码,以帮助:

Ext.define('treeStore', 
{ 
    extend : 'Ext.data.TreeStore', 
    alias: 'widget.treeStore', 
    autoLoad : false, 
    model : 'treeModel', 
    root : { 
     id: 0, 
     name : 'Root', 
     expanded : true, 
     loaded: true 
    }, 
    proxy : { 
     type : 'ajax', 
     url : 'MyServlet', 
     reader : { 
      type : 'json', 
      root : 'children' 
     } 
    }, 
    folderSort: true 
}); 

Ext.define('Ext.tree.Panel',{ 
. 
. 
. 
//Stuff about the tree panel etc. 
dockedItems: { 
     xtype: 'textfield', 
     name: 'Search', 
     allowBlank: true, 
     enableKeys: true, 
     listeners: { 
      specialkey: function (txtField, e) { 
       if (e.getKey() == e.ENTER){ 
        var searchValue = txtField.getValue(); 
        Ext.Ajax.request({ 
         url: 'MyServlet', 
         params: { 
          caseType: 'search', 
          value: searchValue 
         }, 
         success: function(response) { //ATTENTION: When calling the .expand() the AJAX hasn't finished and cannot find the node. 
          response = Ext.decode(response.responseText); 
          var panel = txtField.up(); 
          response.IDs.forEach(function(entry){ 
           panel.getStore().getNodeById(entry.folderId).expand(); <-problem here 
          }); 
         } 
        }); 
       } 
      } 
     } 
    } 

我已经尝试添加功能展开()回调,我已经试过DelayedTask的,我试过的SetTimer等,但没有作品。我真的没有选择,这似乎是这样一个简单的事情,但它使我发疯。

回答

1

这里与重更新的解决方案,以帮助人们了解评论是怎么回事:

TreePanel: { 
    a: {}, 
    bunch: {}, 
    of: {}, 
    stuff: {}, 

    dockedItems: { 
     xtype: 'textfield', 
     name: 'Search Field', 
     allowBlank: true, 
     enableKeys: true, 
     listeners: { 
      specialkey: function (textfield, keypressEvent) { 
       if (keypressEvent.getKey() == keypressEvent.ENTER) { 
        treePanelReference.searchFunction(textfield.getValue()); 
       } 
      } 
     } 
    }, 

    searchFunction: function (searchKey) { 
     var treepanel = this; //Keeping a reference on the treepanel to have access to its functions inside the `success` callback. 
     Ext.Ajax.request({ 
      url: '/api/folders/search', 
      params: { 
       value: searchKey 
      }, 
      success: function(response) { 
       response = Ext.decode(response.responseText); 
       treepanel.expandFn(-1, response); 
      }; 
     }); 
    }, 

    expandFn: function(index, response) { //Recursive function. 
     var folders = response.folders;//This array contains all the folders of the path ordered from the root folder to the one we are searching for. 
     var node = this.getStore().getNodeById(folders[folders.length-1].folderId);//Attempt to fetch the selected folder (it is the last folder in the array) if it has been loaded. 
     if (!node) {//If it can't find the node it means it hasn't been loaded, we have to load each folder on the path one by one until we find the one we are looking for. 
      var i = index + 1; 
      var nextNode = this.getStore().getNodeById(folders[i].folderId); 
      if (!nextNode.isExpanded() && !nextNode.isLoaded()) { //If we arrive at a folder that isn't loaded we have to load it. 
       //Because loading takes time, all actions that are to take place after the load are put in this callback function 
       //that will be called after the folder has been loaded and expanded. 
       //We use Ext.pass to have easier control over the scope and arguments. 
       //We also add {single: true} so that the function isn't called again if we manually reload the node at some point. 
       nextNode.on("expand", Ext.pass(this.expandFn, [this, i, response]), this, {single:true}); 
       nextNode.expand(); 
      } 
      else if (!nextNode.isExpanded() && nextNode.isLoaded()) {//If the folder has been loaded but not expanded we simply expand it. 
       nextNode.expand(); 
       this.expandFn(this, i, response); 
      } 
      else { 
       //Every call to expandFn is made in order to load the next folder on the path, 
       //recursively until we end up loading its immediate parent node at which point 
       //we exit the recursion. 
       this.expandFn(this, i, response); 
      } 
     } 
     else { 
      //We arrive here if in the previous recursion step we ended up loading the searched folder's immediate parent 
      //and the call to `getNodeById` returns the folder we're looking for. 
      //Here we expand the whole path (it might not be expanded fully) up to the folder we are searching for and we also select and focus it. 
      this.expandPath(node.getPath(), {select: true}); 
     } 
    } 
} 
4

如果你要的getPath

var path = node.getPath(); 

的路径,要展开节点,例如从以前的调用保存的那么那么的任务很简单:

tree.expandPath(path); 

您可以测试此通过在控制台输入在http://docs.sencha.com/extjs/4.2.2/extjs-build/examples/build/KitchenSink/ext-theme-neptune/#tree-reorder方法:

Ext.ComponentQuery.query('treepanel[title=Files]')[0].expandPath('/Ext JS/app/domain', 'text'); 

的任务是多一点cumb如果您没有路径,但是您决定在父级展开(加载)之后要展开哪个子级,则可能会非常普遍。在这种情况下,您可能会使用callback函数进行扩展,并继续在回调中扩展孩子。

node.expand的细节