繁体   English   中英

ExtJS 4中的范围在函数处理程序中

[英]Scope in ExtJS 4 inside a function handler

我已经对范围问题进行了一些搜索,发现了一些东西,但我不确定它们是否适用于我的情况。 我真的很困惑,所以我想我不妨直接问论坛。

我有一个树面板。 在该树面板中,我有一个xtype的dockedItem:'textfield'。 该textfield接受一个值,并通过在特殊键事件的处理程序内的Ext.Ajax.Request将其用作ajax请求中的参数。 服务器在其响应上返回一个JSON对象,该对象将被解码并包含树节点的文件夹ID。 在ajax请求的SUCCESS配置中,有一个我想要运行的函数,它必须通过getNodeById(IdFromAjaxResponse)引用树的节点并展开它们。 问题是我不知道如何引用这些节点。 我试过this.getStore()。getNodeById但事实证明'this'指的是窗口(我猜我的容器是树面板???)。 我如何参考树面板或树存储? 我不想使用像getCmp等直接推荐。

一些代码可以帮助:

Ext.define('treePanel', {
    extend: 'Ext.tree.Panel',
    alias: 'widget.folderTreePanel',
    //title: 'Folder Tree',
    displayField: 'name',
    rootVisible: false,
    store: 'treeStore'
    dockedItems: {
        xtype: 'textfield',
        name: 'Search',
        allowBlank: true,
        enableKeys: true,
        listeners: {
            specialkey: function (txtField, e) { //This handler will essentially take the search value and return the path from the DB
                if (e.getKey() == e.ENTER){
                    var searchValue = txtField.getValue();
                    Ext.Ajax.request({
                        url: 'MyServlet',
                        params: {
                            caseType: 'search',
                            value: searchValue
                        },
                        success: function(response) {
                            response = Ext.decode(response.responseText);
                            var node, i=0;
                            expandFn = function () {
This is where I have a problem->node = this.up('treePanel').getStore().getNodeById(response.IDs[i].folderId);
                                node.expand();
                                i++;
                                if (i >= response.IDs.length-1) return;
                                expandFn();
                            }
                        }
                    });
                }
            }, scope: this
        }
    },
    columns: [{
        xtype: 'treecolumn',
        text: 'Folder Name',
        flex: 2,
        sortable: true,
        dataIndex: 'name'
    },{
        text: 'Folder ID',
        dataIndex: 'id',
        flex: 2,
        sortable: true
    }]
});

编辑:我找到了答案。 每个事件都将触发它的实例作为参数传递给处理函数。 在这种情况下, txtField指的是文本字段本身。 然后我可以遍历继承并找到面板。

但是现在有一个新问题。 expandFn()被调用ONCE然后停止,因为'node'未定义。 它应该递归,直到响应数组中没有更多项。 我认为这是一个范围问题,但我真的很困惑,我似乎没有看到出错...

listeners配置具有属性scope 您可以将其设置为树面板。

[编辑]里面的specialkey监听器,分配this一个变量。 success回调中,范围与特殊键的侦听器中的范围不同。 请参阅下面的修改代码。

listeners: {
   scope: this,
   specialkey: function (txtField, e) { 
            var me = this;
            if (e.getKey() == e.ENTER){
                var searchValue = txtField.getValue();
                Ext.Ajax.request({
                    url: 'MyServlet',
                    params: {
                        caseType: 'search',
                        value: searchValue
                    },
                    success: function(response) {
                        response = Ext.decode(response.responseText);
                        var node, i=0;
                        expandFn = function () {
                            node = me.getStore().getNodeById(response.IDs[i].folderId);
                            node.expand();
                            i++;
                            if (i >= response.IDs.length-1) return;
                            expandFn();
                        }
                    }
                });
            }
}

问题是,你的示波器this指的是目前的范围定义的树形面板时。 在即将定义此树面板时,无法将范围设置为树面板的实例。

要解决此问题,您可以将initComponent函数添加到树面板并在其中设置dockedItems配置:

Ext.define('treePanel', {
    extend: 'Ext.tree.Panel',

    // [...]

    initComponent: function() {
        this.dockedItems = {
            // [...]
        };

        this.callParent();
    }
});

区别在于initComponent是树面板的成员函数,在组件实例化期间由框架自动调用。 这时你已经有一个实例this ,你可以作为使用scope的文本框的监听器。

它已经超过一年了,现在对extjs和javascript基础知识更加熟练。 以下是回答这个问题时应该知道的一些事情:

this - >在javascript中总是引用调用我们使用它的函数的对象。 在我的情况下,由于函数是ajax请求的success callback ,因此无法引用treepanel 要解决此类问题,最好在函数顶部设置对您希望能够访问的对象的引用。 在我的情况下,我可以做var treepanel = txtField.up('treePanel'); 获得对面板的引用。

expandFn - >首先, expandFn是在成功回调中定义的,这是另一个函数。 这会创建一个closure ,我们不希望如此。 如果我们不准备处理它,闭包提供了一些可能导致问题的特殊功能。 treePanel的范围内,使用expandFn并在外部定义它。 这里最基本的问题是node = this.up('treePanel')... this关键字再一次没有引用我认为它的txtField 这就是我们之前定义treePanel原因。 我们可以通过它访问商店。 node.expand()需要时间来完成,特别是如果节点没有加载,我们必须发出服务器请求。 对于这种情况,执行递归的正确方法是添加一个侦听器:

node.on('expand', Ext.bind(treePanel.expandFn, treePanel, [args]), treePanel, {single:true})

有些事情需要注意:

  • 如果我们想要将expandFn DIFFERENT参数传递给默认情况下由expand事件传递的参数,我们必须使用Ext.bind 如果我们编写了node.on('expand', treePanel.expandFn, treePanel, {single:true})那么当expand事件被触发时,它将触发expandFn但是它的默认参数根据文档是扩展节点本身和eOpts事件选项对象。
  • 我们添加{single: true}以确保expandFn仅在下一个'expand'事件中触发。 我们不希望每次扩展节点时都触发它。
  • 在使用node.expand()之前必须添加此侦听器。

这个答案不能完全应用于上面提供的代码,但它解释了它的问题以及应该如何解决它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM