PDA

View Full Version : Damn scoping, what am I missing??



aacoro
19 Aug 2011, 7:19 AM
Hi guys,

I'm testing some things and I thought that I fully understand scoping but I have a issue:

See the following code:


Ext.define("MyCompany.MyScheduler", {
extend : 'Sch.panel.SchedulerGrid',
tbar : [
{
xtype : 'buttongroup',
columns : 3,
title : Your menu,
items : [
{
iconCls : 'icon-prev',
handler : function() {
this.shiftPrevious();
}
},
{
text : 'Date',
menu : Ext.create('Ext.menu.DatePicker', {
handler : function(datePicker, pickedDate) {
var startDateTime = new Date(pickedDate);
startDateTime.clearTime();
startDateTime.setHours(5);
var endDateTime = startDateTime.clone();
endDateTime.setHours(21);
return schPanel.switchViewPreset('pnViewPreset', startDateTime, endDateTime);
}
})
},
{
iconCls : 'icon-next',
handler : function() {
this.shiftNext();
}
}
]
}
],
initComponent : function() {
Ext.apply(this, {
// Setup your static columns
columns : [
{ header : 'Header1', sortable: true, width: 150, dataIndex : 'Header1' },
{ header : 'Header2', sortable: true, width: 100, dataIndex : 'Header2 }
]
});

this.callParent(arguments);
}
});

the problem is
this.shiftNext() AND this.shiftPrevious()
In both cases it is telling:

Uncaught TypeError: Object [object Object] has no method 'shiftNext'

If I place the entire tbar code in:

Ext.apply(this, { // Setup your static columns
columns : [
{ header : 'Header1', sortable: true, width: 150, dataIndex : 'Header1' },
{ header : 'Header2', sortable: true, width: 100, dataIndex : 'Header2 }
]
});

this.callParent(arguments);

Then it is working, but this is a workaround, the real bug is me, i still do not understand it in this context...

This class is called from another JavaScript file like this:

var scheduler = Ext.create("MyCompany.MyScheduler", {
dndValidatorFn : this.validatorFn,
viewConfig : {stripeRows : false, forceFit: true}
})

:((

stevil
19 Aug 2011, 7:51 AM
I don't see a definition for shiftNext or shiftPrevious in your examples, so I can't tell where the scope mismatch lies.

Usually, though, the scope of a button in a toolbar will be the button, though, so you might have to walk the ownerCt chain or use up('xtype of your panel') to get to a containing panel. Try "alert(Ext.ClassManager.getDisplayName(this));" in your handler to confirm.

stevil

aacoro
19 Aug 2011, 9:51 AM
The definition is from Bryntum: http://bryntum.com/docs/#/api/Sch.panel.SchedulerGrid-method-shiftNext

h (http://bryntum.com/docs/#/api/Sch.panel.SchedulerGrid-method-shiftNext)mm but alerting is giving me the following error:


Uncaught TypeError: Object #<Object> has no method 'getDisplayName'

If I console.log(this) i get the following result:

DOMWindow

Why is the DOMWindow the scope?

mankz
20 Aug 2011, 3:45 AM
Scope is tricky, until you get it :)

You have to put scope specific code in a template method (constructor, initComponent, onRender, etc) where you can get access to the component instance.

All you need to think about to figure out the scope is: What is 'this' when the relevant function is parsed.




alert('Right now, "this" is ' + this);
Ext.define("MyCompany.MyScheduler", {
extend : 'Sch.panel.SchedulerGrid',
tbar : [
{
xtype : 'buttongroup',
columns : 3,
title : Your menu,
items : [
{
iconCls : 'icon-prev',
handler : function() {
this.shiftPrevious();
}
},
{
text : 'Date',
menu : Ext.create('Ext.menu.DatePicker', {
handler : function(datePicker, pickedDate) {
var startDateTime = new Date(pickedDate);
startDateTime.clearTime();
startDateTime.setHours(5);
var endDateTime = startDateTime.clone();
endDateTime.setHours(21);
return schPanel.switchViewPreset('pnViewPreset', startDateTime, endDateTime);
}
})
},
{
iconCls : 'icon-next',
handler : function() {
this.shiftNext();
}
}
]
}
],
initComponent : function() {
alert('Right now, "this" is ' + this);
Ext.apply(this, {
// Setup your static columns
columns : [
{ header : 'Header1', sortable: true, width: 150, dataIndex : 'Header1' },
{ header : 'Header2', sortable: true, width: 100, dataIndex : 'Header2 }
]
});

this.callParent(arguments);
}
});


In code above, as the class definition is parsed, the code is running in the global context - hence 'this' will point to the window object. But when you create an instance of a class, inside its constructor and any following method calls, 'this' will point to the instance.

mankz
20 Aug 2011, 3:46 AM
You'll also need to add this to maintain the scope pointing to the component instance:



{
iconCls : 'icon-prev',
scope : this,
handler : function() {
this.shiftPrevious();
}
},

aacoro
20 Aug 2011, 11:59 AM
Yeah, thanks, this was my missing link. My code was refering to this in the global context...

I can work this one out now =D>