Matt Jenkins
Matt Jenkins

Reputation: 3091

Dynamically creating and adding components in initComponent

I have a view that configures its items dynamically. Those child items also configure themselves dynamically.

I'm trying to use initComponent, but in the code below, the merest presence of initComponent on the childItem results in an error ("Cannot read property 'length' of undefined").

Without initComponent on the childItem, the rest works.

What's going wrong with this? Is there an alternative approach?

Ext.define('myapp.view.MyView', {
    extend: 'Ext.container.Container',

    initComponent: function () {
        var me = this;

        var childItem = {
            xtype: 'container',

            initComponent: function () {
                var me = this;
                // I want the childItem to do some configuration here.
                me.callParent();
            }
        };

        me.items = [
            childItem
        ];

        me.callParent();
    }
});

Upvotes: 1

Views: 6749

Answers (3)

wantok
wantok

Reputation: 995

You can use the undocumented xhooks config for Components. See this.

Ext.ComponentManager.create({
    xtype: 'panel',
    xhooks: {
        initComponent: function() {
            console.log('in local override for this specific instance of panel');
            this.items = [{
                xtype: 'panel',
                xhooks: {
                    initComponent: function() {
                        console.log('in local override for this specific instance of panel');
                        this.items = [{html: 'hi'}];
                        this.callParent();
                    }
                }
            }];
            this.callParent();
        }
    }
}, 'panel');

During the component creation process, when Ext sees an xhooks property it overrides the current instance's functions with the matching functions contained in the xhooks config. This ensures that callParent works.

Upvotes: 3

kevhender
kevhender

Reputation: 4405

You are not extending an Ext.Container correctly in your code. If you want to override initComponent, use Ext.define to define your class first:

Ext.define('MyContainer', {
    extend: 'Ext.Container',
    alias: 'widget.my-ct',

    initComponent: function () {
        var me2 = this;
        // I want the childItem to do some configuration here.
        me2.callParent();
    }
});

Ext.define('myapp.view.MyView', {
    extend: 'Ext.container.Container',

    initComponent: function () {
        var me = this;

        var childItem = {
            xtype: 'my-ct'
        };

        me.items = [
            childItem
        ];

        me.callParent();
    }
});

EDIT:

As a best practice, you should always define your classes in separate files. I thought that this would be common sense and just wanted to explain why your original code was in error, but the comment section complained so I've changed this to use more appropriate code.

Upvotes: 2

rixo
rixo

Reputation: 25041

callParent will work only with methods that have been passed through Ext.define (or a close equivalent). Here, you're doing a "runtime" override, so callParent won't work for the children.

Your most next-developer-friendly option is to turn those into legitimate Ext overrides. You can use anonymous classes for simplicity's sake. Example:

var childClass = Ext.define(null, {
    extend: 'Ext.container.Container'

    ,initComponent: function() {

        // Here that will work
        this.callParent(arguments);
    }
});

var childItem = new childClass;

// ...

The other option is to do the work of callParent yourself by calling the parent method in the right scope. The catch here is that you must know how to access the parent method, however this option is nice for bragging about your javascript skills since it will result in some barbarian syntax most (non javascript) developers won't be able to figure out ;) In your case, replace this.callParent() in your child with:

Ext.container.Container.prototype.initComponent.apply(this, arguments);

In both cases, don't forget that you must require Ext.container.Container. In the first case, that will ensure the code runs synchronously, and in the second case it will avoid it to crash on undefined class.

Upvotes: 0

Related Questions