PDA

View Full Version : Question about 'this' and 'scope' in button handlers.



JeanNiBee
6 Apr 2011, 8:26 AM
Hi

I have create a formpanel with username / password fields and a submit / cancel button. All they do is create a LoadMask on top of the form to say if the submit or reset button is clicked.

I HAVE tried reading the soucecode for constructors vs Ext.extends but I got a little lost in it and was wondering if someone could shed some high level light while I attempt to re-read it and absorb what's happenning.

When I create a form passing my config options into the constructor (new Ext.formFormPanel({ // configs as a closure here }) the handler for the buttons returns an error "this.el" is undefined.

Ex:


var helloWorldForm = new Ext.form.FormPanel( (function () {

var submit = function () {
Ext.Msg.alert('Submit Form', '(PRIV) The form has been submitted');
}

var reset = function () {
Ext.Msg.alert('Reset Form', '(PRIV) The form has been reset');
}

// Create a button.

return {
renderTo: 'canvas',
title: 'Hello World form',
layout: 'form',
autoHeight: true,
buttons: [{
name: 'submit',
text: 'Submit',
handler: function () {
submit();
}
},{
name: 'reset',
text: 'Reset',
scope: this,
handler: function () {
this.el.mask('The form was reset...');
}
}],
items: [{
xtype: 'textfield',
fieldLabel: 'Username',
emptyText: 'Enter username here',
inputType: 'text',
name: 'username',
value: '',
listeners: {
focus: function( cmp ) {
cmp.setValue('');
}
}
},{
xtype: 'textfield',
fieldLabel: 'Password',
inputType: 'password',
name: 'password',
value: ''
}]
}
}()));

helloWorldForm.show();

When I create the form extending Ext.form.FormPanel usinf Ext.extend() it works fine.

Ex:


jb.AbstractFormPanel = Ext.extend( Ext.form.FormPanel, function () {
// private stuff here.

return {
title: 'Sample Login Form.',
renderTo: 'canvas',
defaultType:'textfield',
autoScroll: false,
frame: true,
labelWidth: 75,
submitUrl: null,
submitT: 'Submit',
cancelT: 'Cancel',
defaults: {
anchor: '-10'
},
initComponent: function() {

var config = {};

this.buildConfig(config);

Ext.apply( this, Ext.apply( this.initialConfig, config ));

jb.AbstractFormPanel.superclass.initComponent.call( this );

},
buildConfig: function ( config ) {
this.buildItems( config );
this.buildButtons( config );
this.buildTbar( config );
this.buildBbar( config );
},
buildItems: function ( config ) {
config.items = [{
xtype: 'textfield',
fieldLabel: 'Username',
emptyText: 'Enter username here',
inputType: 'text',
name: 'username',
value: '',
listeners: {
focus: function( cmp ) {
cmp.setValue('');
}
}
},{
xtype: 'textfield',
fieldLabel: 'Password',
inputType: 'password',
name: 'password',
value: ''
}]
},
buildButtons: function ( config ) {
config.buttons = [{
text: this.submitT,
scope: this,
handler: this.onSubmit
},{
text: this.cancelT,
scope: this,
handler: function() {
this.el.mask('This form is canceled');
}
}];
},
buildTbar: function ( config ) {
config.tbar = undefined;
},
buildBbar: function ( config ) {
config.bbar = undefined;
},
onSubmit: function () {
Ext.MessageBox.alert('Submit', this.submitUrl);
},
onCancel:function () {
this.el.mask('This form is canceled');
}
};
}());

crysfel
6 Apr 2011, 9:12 AM
Hi there!

In the first example, when you set the scope (scope: this) your setting the scope to the window object, that's because "this" is referencing the windows object witting the anonymous function.

In the second example, your setting the scope to the "instance" of "jb.AbstractFormPanel"!

I hope this help.

JeanNiBee
6 Apr 2011, 10:05 AM
Hi

Thanks for the reply.

I guess what I'm really stuck on is not so much what is happening but why, baring small differences in teh code in both cases I"m using a closure to create a formpanel, one as a parameter to the constructor of FormPanel and the other using Ext.extends...

Why isn't the scope of this being the panel itself being preserved in both cases?

Looking at scope / 'this' rules: for js any function executed as a function makes 'this' be the global object unless it's executed as a method, then it's the calling object... knowing that I'm still not sure why this isn't just the object (FormPanel) in both examples I pasted above.

crysfel
6 Apr 2011, 10:31 AM
Ok, in the first example when you set the scope, the instance of the object that you are creating doesn't exist yet, that's why it doesn't work, at that point you can't set the correct scope and the "this" var points to the global window. However if you want this to work you need to set the scope to the "helloWorldForm" object, that is the var that hold the object that you need.

This works because you're setting the scope to the REAL instance of FormPanel:


{
name: 'reset',
text: 'Reset',
scope: helloWorldForm, //<--- set the correct scope
handler: function () {
this.el.mask('The form was reset...');
}


On the other hand, when you use "Ext.extend" the instance of the object that you are creating exist!!! this is because you are inside of it!! and the "this" now point to the object itself!! you don't need to set the scope to "helloWorldForm" var in this case.

I hope this help and I hope you can understand what im saying.... my english is not as good as I'd like :( however if you speak spanish I can explain you with more detail :)

steffenk
6 Apr 2011, 10:54 AM
both patterns you use are overcomplicated and not the correct way in Ext3, and it'S also not the way to go in Ext4.

You don't need the closures, and you don't need to extend for the purpose you use. Just create a new object as instance of FormPanel. You also don't need to overwrite constructor or initComponent for what you are doing there.

Then you simply use this as scope in handler and call functions of your component, that's all. I gzess you are looking for the scope of the formpanel itself, have a look to the form examples in Ext4, you even don't need the scope if you do the correct ComponentQuery.

ah sry, was Ext3 only, but answer is still valid.

JeanNiBee
6 Apr 2011, 11:29 AM
both patterns you use are overcomplicated and not the correct way in Ext3, and it'S also not the way to go in Ext4.

You don't need the closures, and you don't need to extend for the purpose you use. Just create a new object as instance of FormPanel. You also don't need to overwrite constructor or initComponent for what you are doing there.

Then you simply use this as scope in handler and call functions of your component, that's all. I gzess you are looking for the scope of the formpanel itself, have a look to the form examples in Ext4, you even don't need the scope if you do the correct ComponentQuery.

ah sry, was Ext3 only, but answer is still valid.

Hi

The pattern I am using here is based on the ones published by Jay Garcia and Joe Sakalos, and from what I understand seen as a 'decent' (or not correct way of extending components in Ext 3 at the least).

Please understand that this example is a 'scaled' down version of production code that is more indicative of needing extensions of this form.

I would love to see an alternative if you have the time.

Thanks.

-
John

mitchellsimoens
6 Apr 2011, 11:41 AM
It's an old way of extending but the current "Sencha" way is to do this along with some things I suggest:


myForm = Ext.extend(Ext.form.FormPanel, {
renderTo : 'canvas',
title : 'Hello World form',
autoHeight : true,

initComponent: function() {
Ext.apply(this, {
buttons : this.buildButtons(),
items : this.buildItems()
});

myForm.superclass.initComponent.call(this);
},

buildButtons: function() {
return [{
name : 'submit',
text : 'Submit',
handler : function () {
submit();
}
},{
name : 'reset',
text : 'Reset',
scope : this,
handler : function () {
this.el.mask('The form was reset...');
}
}];
}
buildItems: function() {
return [{
xtype : 'textfield',
fieldLabel : 'Username',
emptyText : 'Enter username here',
name : 'username',
listeners : {
focus : function( cmp ) {
cmp.setValue('');
}
}
},{
xtype : 'textfield',
fieldLabel : 'Password',
inputType : 'password',
name : 'password'
}]
}
});

JeanNiBee
6 Apr 2011, 12:24 PM
I should note that the example I posted, was mainly a 'scaled' down version of production code that had a lot of extensions added to it that would in fact require a complex extension model / pattern like the one shown here. Incidentally this pattern was blatantly copied / derived from the articles by Jay Garcia and Joe Sakalos, both of whom I think are very knowledgeable wrt Ext.

Although the opinions and suggest are ALWAYS welcome, I hope we don't sidetrack the original Topic of the thread and cloud the initial conversation.

(Of which I'll have a comment about when I get home.)

Thanks

-John