在ExtJS中递归扩展树节点

时间:2014-05-23 10:05:51

标签: recursion extjs tree panel

我正在寻找一种递归扩展树节点的方法。树没有被装满。我们一次只加载一个深度级别。因此,例如,如果我的路径有3个级别(/ nodeId1 / nodeId14 / nodeId142)深度我想加载第一个节点,那么通过路径中的第二个ID(在本例中为nodeId14)获取2级节点展开它,然后得到第3等。

然而,当一个节点被扩展时,代理会有一个AJAX调用来获取节点子节点的数据,并且由于这个调用是异步的,程序本身会尝试继续扩展下一级节点,在请求有时间完成给我一个节点未定义的错误'因为2级还没有加载。

我一直在寻找如何解决这个问题的一天,但没有任何帮助。我发现一个博客解决了同样的问题,但帖子是从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
                            });
                        }
                    });
                }
            }
        }
    }

我已尝试向expand()回调添加函数,我尝试过延迟任务,我尝试过setTimer等但没有任何作用。我真的没有选择,这似乎是一件很简单的事情,但它让我疯狂。

2 个答案:

答案 0 :(得分: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');

如果您没有路径但是在扩展(加载)父级之后您决定要扩展哪个子级,则任务会更麻烦一些。在这种情况下,您可能会使用callback函数进行扩展,并继续扩展回调中的子项。

有关详细信息,请参阅node.expand

答案 1 :(得分: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});
        }
    }
}