1

Coming from a C++ background, I'm getting a little lost in Javascript/ExtJS function scoping - specifically when dealing with events.

Say I have a controller which listens in on many different events. These events could come from managed views, stores, application-level, ect. Currently, I'm doing something like this to ensure correct scoping:

init: function() {
    me.control({
        'someSelector': {
            someEvent: me.onSomeEvent.bind(me)
        },
        ...
    });
    me.application.on({
        applicationEvent: me.onApplicationEvent.bind(me)
    });
},
onSomeEvent: function() {...},
onApplicationEvent: function() {...},

Is this the correct way of going about things? I'm scared of using this inside onSomeEvent() and onApplicationEvent unless I know specifically what this is pointing to. Thoughts?

edit: here's some example code to show where this may be misleading.

init: function() {
    this.control({
        'uploadform *': {
            formUpload: this.onFormUpload
        }
    });
},

onFormUpload: function(form) {
    if(form.isValid()) {
        var formData = form.getValues();
        Ext.Ajax.request({
            url: 'upload',
            method: 'POST',
            jsonData: {
                form: formData
            },
            success: this.onFormUploadSuccess // here, this is the controller
        });
    }
},

onFormUploadSuccess: function() {
    ...                                       // here, this isn't the controller
    this.application.fireEvent('dealAdded');  // this.application === undefined!!
}
Colin
  • 1,835
  • 4
  • 24
  • 29

1 Answers1

3

Although scoping can be confusing in JS don't be scared of it. Your controller maintains scope, so you don't need to uglify your code. It should look like this:

Ext.define('Pandora.controller.Station', {
    extend: 'Ext.app.Controller',
    ...    
    init: function() {
        this.control({
            'stationslist': {
                selectionchange: this.onStationSelect
            },
            ...
        });
    },    
    ...    
    onStationSelect: function(selModel, selection) {
        this.application.fireEvent('stationstart', selection[0]);
    },    
   ...
});

An excellent event handling post is here: Explain ExtJS 4 event handling . Additionally when something is not looking right I resort to console.log(this) just to make sure I am looking at the correct scope.

EDIT After seeing the example you provided the issue is not in the controller itself but in the Ajax request being async and executing in Window scope by default. ExtJS lets you set scope with scope:this config in the request, which will set the controller as scope for the success callback.

Ext.Ajax.request({
            url: 'upload',
            method: 'POST',
            jsonData: {
                form: formData
            },
            success: this.onFormUploadSuccess // here, this is the controller
     ,scope:this
        });
Community
  • 1
  • 1
dbrin
  • 15,525
  • 4
  • 56
  • 83
  • In your example, for `onStationSelect`, you have no guarantee what `this` is pointing to. I had this exact problem, with `this.application` being `undefined` – Colin Sep 13 '13 at 22:52
  • `(this.onStationSelect)` resolves to a function, (in this case, `onStationSelect`), which is called with some arbitrary context – Colin Sep 13 '13 at 22:54
  • Is this equivalent to doing `success: this.onFormUploadSuccess.bind(this)` ? – Colin Sep 14 '13 at 00:49
  • follow-up: ... whats better? `bind` or `scope` ? – Colin Sep 14 '13 at 01:16
  • I find bind confusing. setting scope is very explicit, i am sure it does bind behind the scenes :) – dbrin Sep 14 '13 at 01:19
  • Ya, tis what I was thinking. Anyways, I thank you for your help as usual :) – Colin Sep 14 '13 at 01:28