Kushal
Kushal

Reputation: 3168

Add change event handler for custom Container of ExtJS

I have created a View by extending Ext.container.Container and have given it an alias widget.myCustomView. Since I'm using it in different places.

The view as usual Ext form components like textfield, dataview, etc. Now I adding this view into other view using xtype as follows:

{
    xtype: 'myCustomView',
    itemId: 'myCustomView'
}

Now, I want to add change event handler such that if any component's change is fired, I can fire the change event of myCustom view. In short, do something like this.

{
    xtype: 'myCustomView',
    itemId: 'myCustomView',
    listeners: {
        'change' : function(viewObj, eOpts) {
             //do something
         }
    }
}

How to do it?

Upvotes: 1

Views: 4365

Answers (1)

rixo
rixo

Reputation: 25001

Use the relayEvents() method to... well, relay the change event from child fields.

Here's some basic code that does that:

Ext.define('My.Container', {
    extend: 'Ext.Container'

    ,layout: 'form'

    ,initComponent: function() {
        this.callParent(arguments);

        // i want to support nested containers
        this.parseContainerItems(this);
    }

    ,onItemAdded: function(item) {
        if (item instanceof Ext.Container) {
            this.parseContainerItems(item);
        } else if (item instanceof Ext.form.field.Base) {
            this.relayEvents(item, ['change']);
        }
    }

    ,parseContainerItems: function(ct) {
        if (ct.items) {
            ct.items.each(this.onItemAdded, this);
        }
    }
});

Example usage:

Ext.create('My.Container', {
    renderTo: 'ct' // render to a test div
    ,height: 200
    ,width: 200

    ,items: [{
        xtype: 'textfield', name: 'foo', fieldLabel: 'Foo'
    },{
        xtype: 'container'
        ,items: [{
            xtype: 'checkbox', name: 'bar', fieldLabel: 'Bar'
        }]
    }]

    ,listeners: {
        change: function(item, newValue, oldValue) {
            console.log(Ext.String.format('Value of item {0} changed from {1} to {2}', item.name, oldValue, newValue));
        }
    }
});

Going further...

As I've said my implementation is quite rudimentary since it only supports fields that are added to the container by configuration. If you want to make that component flexible, you'll have to handle fields that are added after the component creation.

For that you'll need to watch the add event of the container to relay from fields that are added after its creation. The doc says that this event bubbles from child containers, but from my tests it does not :-( So (until that's fixed?) you'll also have to watch the add event of child containers.

Here's the updated code for the parseContainerItems() method:

parseContainerItems: function(ct) {
    ct.on('add', function(me, item) {
        this.onItemAdded(item);
    }, this);

    if (ct.items) {
        ct.items.each(this.onItemAdded, this);
    }
}

If you also want to support the possibility of removing fields dynamically, that's when things will go awry... You'd have to implement your own version of relayEvents() because, as far as I know, it is not possible to stop relaying events with the one provided by Ext. Then you'd have to watch the remove event to remove the listeners you've added to child fields and containers.

Upvotes: 1

Related Questions