views:

64

answers:

2

I am trying to get better at extending the classes of Extjs, and my evolvement have lead me to this problem:

I have extended an Ext.Panel and I want my extension to have a bottom toolbar with one button as default.

myPanel = Ext.extend(Ext.Panel, {
    method: function () {
        return 'response!';
    },

    bbar: new Ext.Toolbar({
        items:
        [
            {
                xtype: 'button',
                text: 'Hit me!',
                handler: function (button, event) {
                    alert(this.method());
                },
                scope: this
            }
        ]
    })
});

What I haven't learnt yet is why this is not allowed. this is pointing at the global scope and not my extended panel - thus .method() is undefined inside the handler function.

+4  A: 

You're defining the bbar on the prototype rather than on a specific object.

Override initComponent and move the bbar definition inside it.

myPanel = Ext.extend(Ext.Panel, {
    method: function () {
        return 'response!';
    },

    initComponent: function() {    
        var bbar = new Ext.Toolbar({
            items:
            [
                {
                    xtype: 'button',
                    text: 'Hit me!',
                    handler: function (button, event) {
                        alert(this.method());
                    },
                    scope: this
                }
            ]
        });

        // Config object has already been applied to 'this' so properties can 
        // be overriden here or new properties (e.g. items, tools, buttons) 
        // can be added, eg:
        Ext.apply(this, {
            bbar: bbar
        });

        // Call parent (required)
        myPanel.superclass.initComponent.apply(this, arguments);

        // After parent code
        // e.g. install event handlers on rendered component
    }
});

See http://www.sencha.com/learn/Manual:Component:Extending_Ext_Components for a template you can use when extending components

ob1
+1  A: 

You have to keep in mind that the anonymous object that is the first element of the items array is created in the same scope as the one in which Ext.extend(... is executed.

If you had this:

var o = { 'a': a, 'b': b, scope: this };

you would expect that o.a, o.b, and o.scope would have the same values as a, b, and this in the current scope. Here, it's a little more complex because you are creating an object while creating an array while creating an object, etc., but the reasoning is the same.

What you should do instead is define this.bbar inside the constructor:

myPanel = Ext.extend(Ext.Panel, {
    method: function () {
        return 'response!';
    },

    constructor: function(config) {
        this.bbar = new Ext.Toolbar({
            items:
            [
                {
                    xtype: 'button',
                    text: 'Hit me!',
                    handler: function (button, event) {
                        alert(this.method());
                    },
                    scope: this
                }
            ]
        });

        myPanel.superclass.constructor.apply(this, arguments);
    }
});
Daniel Trebbien