问题
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...
回答1:
The listeners
config has a property scope
. You can set that to the Tree Panel.
[Edit] Inside the specialkey listener, assign this
to a variable. Inside the success
callback, the scope is different from the one in the listener for specialkey. See the modified code below.
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:
The problem is, that your scope this
refers to the current scope when the tree panel is defined. You cannot set the scope to an instance of the tree panel when this tree panel is just about to be defined.
To solve this problem you can add a initComponent function to your tree panel and set the dockedItems config there:
Ext.define('treePanel', {
extend: 'Ext.tree.Panel',
// [...]
initComponent: function() {
this.dockedItems = {
// [...]
};
this.callParent();
}
});
The difference is that initComponent
is a member function of your tree panel which is called automatically by the framework during the instantiation of the component. At this time you already have an instance this
which you can use as the scope
of your textfield's listener.
回答3:
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 toexpandFn
than those passed by theexpand
event by default. If we wrotenode.on('expand', treePanel.expandFn, treePanel, {single:true})
then when theexpand
event fired it would fireexpandFn
but with its default arguments which according to the documentation are the expanded node itself and aneOpts
event options object. - We add
{single: true}
to make sureexpandFn
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.
来源:https://stackoverflow.com/questions/23805184/scope-in-extjs-4-inside-a-function-handler