PDA

View Full Version : Understanding scoping - targeting a parent



DaveC426913
4 Aug 2010, 12:24 PM
I've got this component repeated dozens of times across multiple containers, so having the touchStartHandler scoped to each button is impractical. How can I point the listener to globaltouchStartHandler?

Seems to me the parent is Concierge.Keypad, but that does not work.



Concierge.Keypad = Ext.extend(Ext.Panel, {

initComponent: function() {
var config = {

fullscreen: true,
xtype: 'container',
items: [{
xtype: 'button',
text : 'Click Me',
listeners : {
afterrender : function(){
this.mon(this.el, {
touchstart : this.touchStartHandler,
})
}
},
touchStartHandler: function(button, event){
//process button press
console.log("button pressed...");
},
}]
};

Ext.apply(this, Ext.apply(this.initialConfig, config));
Concierge.Keypad.superclass.initComponent.apply(this, arguments);
},
globaltouchStartHandler: function(button, event){
//process button press
console.log("button pressed...");
}
});
Ext.reg('concierge_keypad', Concierge.Keypad);

hendricd
4 Aug 2010, 3:49 PM
@Dave--

Lets reorg just a bit (keeping your event handlers together in the class):



Concierge.Keypad = Ext.extend(Ext.Panel, {

initComponent: function() {
var me =this; //shortcut reference to 'this'
var config = {

fullscreen: true,
xtype: 'container',
items: [{
xtype: 'button',
text : 'Click Me',
listeners : {
afterrender : function(){
this.mon(this.el, {
touchstart : me.touchStartHandler,
tapcancel : me.touchEndHandler, //if finger moves off button after tapstart
touchend : me.touchEndHandler,
scope : me
})
}
}
}]
};

Ext.apply(this, Ext.apply(this.initialConfig, config));
Concierge.Keypad.superclass.initComponent.apply(this, arguments);
},
touchStartHandler: function(button, event){
//process button press
console.log("button pressed...");
},

touchEndHandler: function(button, event){
//process button press
console.log("button pressed...");
}
});
Ext.reg('concierge_keypad', Concierge.Keypad);

DaveC426913
5 Aug 2010, 5:46 AM
So let me see if I understand what you've done here (thinking out loud).

this is a generic, relative pointer that always points to the calling object of the code in which it is found (this is context-sensitive and will change regularly).

My code fails because, by the time I invoke this (looking for the root object where my methods are), its context has changed; this now refers to a child object of the root, and my methods are now out of scope.

So, you've made an explicit variable me and assigned it this when it is pointing at the root object, so that me now retains its context (and thus the context of my methods), regardless of where I refer to it.


So, basically, rather than navigating up and down the object structure relatively (parent > grandparent), I simply assign an absolute root (um, Adam?) then navigate down from there.

Thanks!


One thing:

How do I now reference my variables?

This is what I had before:



Concierge.Keypad = Ext.extend(Ext.Panel, {
defaultEntryText: "Please enter...",
initComponent: function() {
var me = this; //shortcut reference to 'this'
this.entryArray[0] = this.defaultEntryText;
...
touchStartHandler: function(button, event){
var def = this.defaultEntryText;
//process button press
console.log("button pressed..."+ def);
},

evant
5 Aug 2010, 5:51 AM
In that case, assigning the variable makes no difference, other than it being a shortcut. You could easily use:



Concierge.Keypad = Ext.extend(Ext.Panel, {

initComponent: function(){
var config = {

fullscreen: true,
xtype: 'container',
items: [{
xtype: 'button',
text: 'Click Me',
listeners: {
afterrender: function(){
this.mon(this.el, {
touchstart: this.touchStartHandler,
tapcancel: this.touchEndHandler, //if finger moves off button after tapstart
touchend: this.touchEndHandler,
scope: this
})
}
}
}]
};

Ext.apply(this, Ext.apply(this.initialConfig, config));
Concierge.Keypad.superclass.initComponent.apply(this, arguments);
},
touchStartHandler: function(button, event){
//process button press
console.log("button pressed...");
},

touchEndHandler: function(button, event){
//process button press
console.log("button pressed...");
}
});
Ext.reg('concierge_keypad', Concierge.Keypad);


The important part is setting the scope on the listeners. The scope parameter indicates the scope in which to execute the listener functions (ie. what does "this" refer to in those functions).

If you don't specify a scope, it will usually default to the component that fired the event (or in some cases, the global window object).

DaveC426913
5 Aug 2010, 6:12 AM
In that case, assigning the variable makes no difference, other than it being a shortcut. You could easily use:

You must have pasted the wrong code. This code still has the wrong scope and also has no variables. (I've edited my post above to highlight my attempt to introduce variables.)

evant
5 Aug 2010, 6:17 AM
The arguments you have in your handlers aren't correct. There is no button object passed, because you're binding the events on the underlying element.

But yes, I made a typo, it should be:



Concierge = {};
Concierge.Keypad = Ext.extend(Ext.Panel, {

initComponent: function(){
var config = {

fullscreen: true,
xtype: 'container',
items: [{
xtype: 'button',
text: 'Click Me',
listeners: {
scope: this,
afterrender: function(){
this.mon(this.el, {
touchstart: this.touchStartHandler,
tapcancel: this.touchEndHandler, //if finger moves off button after tapstart
touchend: this.touchEndHandler,
scope: this
})
}
}
}]
};

Ext.apply(this, Ext.apply(this.initialConfig, config));
Concierge.Keypad.superclass.initComponent.apply(this, arguments);
},
touchStartHandler: function(event){
//process button press
console.log("button pressed...");
},

touchEndHandler: function(event){
//process button press
console.log("button pressed...");
}
});
Ext.reg('concierge_keypad', Concierge.Keypad);

Ext.setup({
onReady: function(){
new Concierge.Keypad({
});
}
});

DaveC426913
5 Aug 2010, 6:23 AM
The arguments you have in your handlers aren't correct. There is no button object passed, because you're binding the events on the underlying element.
Oh no! That's disheartening. That means aaaalllll the code I've written that is dependent on the button has to be rewritten!



But yes, I made a typo, it should be:

How does this change help me use class-level variables? I don't see any in your sample.

evant
5 Aug 2010, 6:25 AM
Concierge = {};
Concierge.Keypad = Ext.extend(Ext.Panel, {

initComponent: function(){
this.awesomeProperty = 'foo';
var config = {

fullscreen: true,
xtype: 'container',
items: [{
xtype: 'button',
text: 'Click Me',
listeners: {
scope: this,
afterrender: function(){
this.mon(this.el, {
touchstart: this.touchStartHandler,
tapcancel: this.touchEndHandler, //if finger moves off button after tapstart
touchend: this.touchEndHandler,
scope: this
})
}
}
}]
};

Ext.apply(this, Ext.apply(this.initialConfig, config));
Concierge.Keypad.superclass.initComponent.apply(this, arguments);
},
touchStartHandler: function(event){
console.log(this.awesomeProperty);
//process button press
console.log("button pressed...");
},

touchEndHandler: function(event){
//process button press
console.log("button pressed...");
}
});
Ext.reg('concierge_keypad', Concierge.Keypad);

Ext.setup({
onReady: function(){
new Concierge.Keypad({
});
}
});

DaveC426913
5 Aug 2010, 6:31 AM
OK. Thanks.

(Man, I thought I knew how to code. But this OO JavaScript might as well be alien. I fear I'm forever doomed to copy and paste from examples...)


head<>desk<>head<>desk

Your example has removed the me reference. Now my methods are out of scope again.