范围在ExtJS 4里面的函数处理程序 [英] Scope in ExtJS 4 inside a function handler

查看:145
本文介绍了范围在ExtJS 4里面的函数处理程序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经搜索了一些关于范围问题的一些东西,但我不知道他们为我的工作。我真的很困惑atm,所以我以为我可以直接问到论坛。



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



有些代码可以帮助:

  Ext.define('treePanel',{
extends:'Ext.tree.Panel',
alias:'widget.folderTreePanel',
// title:'文件夹树',
displayField:'name',
rootVisible:false,
store:'treeStore'
dockedItems:{
xtype:'textfield',
name:'search',
allowBlank:true,
enableKeys:true,
listeners:{
specialkey:function(txtField,e){//这个处理程序本质上获取搜索值并从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(){
这是我有问题的地方 - > node = this.up('treePanel')。getStore()。getNodeById(response.IDs [i] .folderId) ;
node.expand();
i ++;
if(i> = response.IDs.length-1)return;
expandFn();
}
}
});
}
},范围:这个
}
},
列:[{
xtype:'treecolumn',
text:'文件夹名称',
flex:2,
可排序:true,
dataIndex:'name'
},{
文本:'文件夹ID',
dataIndex:'id',
flex:2,
sortable:true
}]
});

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



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

解决方案

以前已经有一年多了,现在我们更加熟练的使用extjs和javascript基础知识。这里有一些应该知道的东西来回答这个问题:



这个 - >在javascript总是指调用我们使用它的函数的对象。在我的情况下,由于函数是ajax请求的成功回调,所以不可能引用 treepanel 。为了解决这个问题,最好在函数顶部设置一个对象的引用。在我的情况下,我可以执行 var treepanel = txtField.up('treePanel'); 以获取面板的引用。



expandFn - >第一件事首先, expandFn 在成功回调中定义,这是另一个功能。这将创建一个闭包,我们不希望这样。关闭提供了一些特殊功能,如果我们无法处理它,可能会导致问题。在 treePanel 的范围内,将 expandFn 定义在外面。这里最基本的问题是 node = this.up('treePanel')... 这个关键字一次再次不是指我认为它的 txtField 。这就是为什么我们更早地定义了 treePanel 的原因。我们可以通过它访问商店。另外 node.expand()需要时间来完成,特别是如果节点没有被加载,而且我们必须做一个服务器请求。对于这种情况,递归的正确方法是添加一个监听器:



node.on('expand',Ext.bind(treePanel



有些事情要注意:




  • 如果要将不同的参数传递给 Ext.bind > expandFn 比通过展开事件默认情况下传递。如果我们写了 node.on('expand',treePanel.expandFn,treePanel,{single:true})然后当展开事件触发它将触发 expandFn ,但其默认参数根据文档是扩展节点本身和 eOpts 事件选项对象

  • 我们添加 {single:true} 确保 expandFn 将仅在下一个'expand'事件触发。我们不希望在每次展开节点时触发。

  • 在我们使用 node.expand()



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


I've searched a little about the scope problem and found some stuff but I'm not sure they work for my case. I'm really confused atm so I thought I might as well ask directly to the forums.

I have a tree panel. Inside that tree panel I have a dockedItem of xtype: 'textfield'. That textfield takes a value and uses it as a parameter in an ajax request via Ext.Ajax.Request inside a handler for the specialkey event. The server returns a JSON object on its response that gets decoded and contains folder IDs of the nodes of the tree. Inside the SUCCESS config of the ajax request there is a function I want to run that has to refer to the nodes of the tree via getNodeById(IdFromAjaxResponse) and expand them. The problem is that I do not know how to refer to those nodes. I tried this.getStore().getNodeById but it turns out 'this' refers to the window (I guess my container for the tree panel???). How do I refer to the tree panel or the tree store? I do not want to use direct referrals like getCmp etc.

Some code to help:

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

EDIT: I found the answer. Each event passes the instance that triggered it as an argument into the handler function. In this case txtField refers to the textfield itself. I can then traverse the inheritance and find the panel.

However there is a new problem now. The expandFn() gets called ONCE and then stops because 'node' is undefined. It is supposed to recurse until there are no more items in the response array. Again I think this is a scope problem but I'm really confused and I don't seem to see the goes wrong...

解决方案

It has since been more than a year and am now much more proficient with extjs and javascript basics in general. Here are some things that one should know to answer the question:

this -> in javascript always refers to the object that called the function in which we use it. In my case since the function was the success callback of the ajax request this could not possibly refer to the treepanel. To solve such problems it is good practice to set a reference to the object you want to be able to access at the top of the function. In my case I could do var treepanel = txtField.up('treePanel'); to get a reference to the panel.

expandFn -> First things first, expandFn is defined inside the success callback which is another function. This creates a closure and we don't want that. Closures provide some special functionality that might cause problems if we're not prepared to deal with it. Take expandFn and define it outside, in the treePanel's scope. The most basic problem here is that node = this.up('treePanel')... the this keyword once again does not refer to the txtField I thought it did. This is why we defined treePanel earlier. We can have access to the store through that. Also node.expand() takes time to complete, especially if the node isn't loaded and we have to make a server request. For that case the correct way to do the recursion is by adding a listener:

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

Some things to note here:

  • We must use Ext.bind if we want to pass DIFFERENT arguments to expandFn than those passed by the expand event by default. If we wrote node.on('expand', treePanel.expandFn, treePanel, {single:true}) then when the expand event fired it would fire expandFn but with its default arguments which according to the documentation are the expanded node itself and an eOpts event options object.
  • We add {single: true} to make sure expandFn will be fired only on the next 'expand' event. We don't want it to fire every time we expand a node.
  • This listener must be added BEFORE we use node.expand().

This answer cannot EXACTLY be applied to the supplied code above, but it explains the problems with it and what should one do to solve it.

这篇关于范围在ExtJS 4里面的函数处理程序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆