【问题标题】:Scope in ExtJS 4 inside a function handler函数处理程序内 ExtJS 4 中的范围
【发布时间】:2014-05-22 11:10:30
【问题描述】:

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

我有一个树面板。在该树面板内,我有一个 xtype: '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() 被调用一次,然后因为“节点”未定义而停止。它应该递归,直到响应数组中没有更多项目。我再次认为这是一个范围问题,但我真的很困惑,我似乎没有看到出错...

【问题讨论】:

    标签: javascript extjs scope extjs4 handler


    【解决方案1】:

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

    [编辑] 在 specialkey 监听器中,将 this 分配给一个变量。在success 回调中,作用域与specialkey 侦听器中的作用域不同。请参阅下面的修改代码。

    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();
                            }
                        }
                    });
                }
    }
    

    【讨论】:

      【解决方案2】:

      问题是,您的范围this 指的是定义树面板时的当前范围。当树面板即将被定义时,您不能将范围设置为树面板的实例。

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

      Ext.define('treePanel', {
          extend: 'Ext.tree.Panel',
      
          // [...]
      
          initComponent: function() {
              this.dockedItems = {
                  // [...]
              };
      
              this.callParent();
          }
      });
      

      不同之处在于initComponent 是树形面板的成员函数,在组件实例化期间由框架自动调用。此时您已经有了一个实例this,您可以将其用作文本字段侦听器的scope

      【讨论】:

      • 我实际上尝试了 initComponent 但我使用了 this.getDockedItems 它告诉我这个函数不存在......这意味着“this”不是指树形面板? ?
      • 您应该可以调用该函数,但我不建议这样做,因为此时组件还没有完全准备好。尝试这样做时收到以下错误:Uncaught TypeError: Cannot read property 'items' of undefined 原因是停靠的项目集合还不存在。请改用this.dockedItems,如我的示例中所建议的那样。
      【解决方案3】:

      从那以后已经有一年多的时间了,现在我对 extjs 和 javascript 基础知识有了更全面的了解。以下是回答问题时应该知道的一些事情:

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

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

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

      这里有几点需要注意:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2014-09-14
        • 1970-01-01
        • 1970-01-01
        • 2017-05-04
        • 1970-01-01
        • 1970-01-01
        • 2022-11-19
        相关资源
        最近更新 更多