Monday, November 19, 2012

Reference of ‘this’ is not required for event handler


One strange thing that I have always seen that  whenever I tried to use ‘this’ keyword in ExtJs in any event handler, I didn't get the expected result. Either I got some unexpected object or sometimes ‘undefined’ in place of ‘this’. E.g.


    Ext.define('CustomClass',{
        config:{
            val:'This is testing',
            panelObj: {}
        },

       constructor: function(){
                ref = this;
       }

        createPanel: function(){
            this.panelObj = Ext.create('Ext.panel.Panel',{
                layout: 'vbox',
                width: 300,
                height: 300,
                items:[
                       {
                                   xtype:'button',
                                   text: 'Click me',
                                   itemId: 'clickMeBtn',
                                   listeners: {
                                                click: function(){
                                                 // this.panelObj.queryById('labelId').setText('Value changed');
                                                 ref.panelObj.queryById('labelId').setText('Value changed');
                                        }
                           }
                       },
                       {
                                   xtype: 'label',
                                   itemId: 'labelId',
                                   text: 'Click on button to change me'
                       }
                      ]               
            });
            return this.panelObj;
        } 
    });


In above code, if we use " this.panelObj.queryById('labelId').setText('Value changed');", I will get some unexpected result. So, I have to keep the reference of 'this' in a 'ref' variable in constructor and then I used this ref variable in the click handler to get required result.

Problem in this approach: But, this is not a good programming approach. Here, we are keeping the reference of 'this' at global level in a 'ref' variable. It will work if the above class is singleton i.e. if we will create only one object of this class in whole application. But, what will happen, if we create more than one object of this class and all the object will be active simultaneously. In this case, the 'ref' variable will contain reference of only last created object and thus using ref variable in event handlers of corresponding objects will give unexpected result.

Solution of this problem: To solve this problem, we can use bind() function provided by ExtJs. With the help of this function, we can directly use 'this' instead of 'ref' in event handler of this class. The bind() function binds a method to an event and accept a scope(may be 'this' or other object) and some more arguments. The syntax of this function is:

bind( fn, [scope], [args], [appendArgs] ) : function

fn: This is a function to be bound with an event.

scope: This is an optional parameter. It is used to provide the scope in which the function will run. E.g. here we can provide 'this' as a scope.

args: This is an optional parameter. It is an array. Overrides arguments for the call. (Defaults to the arguments passed by the caller).

appendArgs: It is an optional and boolean/number parameter. If True args are appended to call args instead of overriding, if a number the args are inserted at the specified position.

Following is the example of how can we modify our above code to use 'this' directly in an event handler  without keeping any reference of 'this' by using bind() function.


    Ext.define('CustomClass',{
        config:{
            val:'This is testing',
            panelObj: {}
        },

        btnClickHandler: function () {
            this.panelObj.queryById('labelId').setText('Value changed');
        },

        createPanel: function(){
            this.panelObj = Ext.create('Ext.panel.Panel',{
                layout: 'vbox',
                width: 300,
                height: 300,
                items:[
                       {
                                   xtype:'button',
                                   text: 'Click me',
                                   itemId: 'clickMeBtn',
                                   listeners: {
                                                click: Ext.bind(this.btnClickHandler, this)
                           }
                       },
                       {
                                   xtype: 'label',
                                   itemId: 'labelId',
                                   text: 'Click on button to change me'
                       }
                      ]               
            });
            return this.panelObj;
        } 
    });


No comments:

Post a Comment

Please provide your precious comments and suggestion