Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In ExtJS components how to forward config: {} items to sub components

I am trying to write a reusable item selection panel where the user has a grid with items he can choose from and a small text field that he can use to filter the content of the grid. Right now the (simplified) view code looks like this and works.

Ext.define('MyApp.view.items.ItemSelectorPanel', {
    extend: 'Ext.panel.Panel',
    require: 'MyApp.view.items.SimpleItemGrid',
    alias: 'widget.ItemSelectorPanel',
    layout: 'form',

    config: {
        itemStore: false
    },

    constructor: function(config) {
        this.initConfig(config);

        this.superclass.constructor.call(this, config);

        this.add([
            {
                fieldLabel: 'Filter',
                name: 'filter'
            },
            {
                xtype: 'SimpleItemGrid',
                collapsible: true,
                store: this.getItemStore()
            }
        ]);

        return this;
    }
});

As you can see the ItemSelectorPanel uses the config property to expose an interface where the calling site can specify which item store to use.

Calling site (in this case the panel is added to a TabPanel):

var panelToAdd = {
    xtype: 'panel',
    title: 'New Selection',
    closable: true,
    padding: 10,
    items: [{
        title: 'Select node',
        xtype: 'ItemSelectorPanel',
        itemStore: itemStore
    }]
};

Now, I love the declarative style of ExtJS 4 and how it helps to follow the MVC pattern. I would prefer to have the least amount of code possible in the views. Unfortunately this does not work:

Ext.define('MyApp.view.items.ItemSelectorPanel', {
    /* ... same as above ... */

    constructor: function(config) {
        this.initConfig(config);

        this.superclass.constructor.call(this, config);

        return this;
    },

    items: [
            {
                fieldLabel: 'Filter',
                name: 'filter'
            },
            {
                xtype: 'SimpleItemGrid',
                collapsible: true,
                store: this.getItemStore   // <-- interesting part
            }
    ]
});

Is there a way to expose the config of a nested/sub component via the config property of the parent property in a declarative manner?

like image 445
ErosC Avatar asked Jan 17 '13 17:01

ErosC


People also ask

What is xType in Ext JS?

xType defines the type of Ext JS UI component, which is determined during rendering of the component. For example, the element can be a textbox for which we have xType as textField or the element can have a numeric value only for which we have Numeric xType.

What is component in Ext JS?

Advertisements. ExtJS UI is made up of one or many widgets called Components. Ext Js has various UI components defined that can be customized as per your requirements.

What is ref in Ext JS?

The refs config creates a getter method on the controller that internally uses Ext. ComponentQuery to fetch the component instance using the configured selector. The following example will add the getList method to the controller and will return the first component in the application hierarchy with an xtype of "grid".

What is CLS Ext JS?

cls: This is applied to the component's root element. Quoting from the docs: An optional extra CSS class that will be added to this component's Element. This can be useful for adding customized styles to the component or any of its children using standard CSS rules.


2 Answers

First something in general

Never add an object outside a function within a class definition unless you exactly know what you are going to do. Cause if you do so all instances will share the same instance of that object. I think I do not need to mention where this leads to...

If you have a need to place a object there you should clone it within the constructor.

To your code

I dunno what this.initConfig(config); does but the config variable is not the one from your class, it is the one from the constructor argument. I recommend you also to use initComponent() for initialization instead of the constructor() unless you have a defined need for using the constructor, which in your case you don't seem to have.

Also a 'config' is not forwarded cause it don't get executed up->bottom but bottom->up where a config get's hand up and all other properties are (already) inherited.

I still do not exactly know what your goal is, therefore I cannot give you any advice how you should do this but I can say for sure that the way you do it will lead to problems.

Edit

I still not sure that I have fully understand your needs but the following should work (if you need the listeners too you might take a look at the Ext.util.Bindable mixin)

Ext.define('MyApp.view.items.ItemSelectorPanel', {
    extend: 'Ext.panel.Panel',
    require: 'MyApp.view.items.SimpleItemGrid',
    alias: 'widget.ItemSelectorPanel',
    layout: 'form',

    initComponent: function() {
        // Initialize the store (might be a instance or a storeId)
        var store;
        if (this.itemStore) {
            store = Ext.data.StoreManager.lookup(store);
        }
        this.itemStore = store || null;
        // Add is not valid (at least not before the parent inits are executed)
        this.items = [{
            fieldLabel: 'Filter',
            name: 'filter'
        }, {
            xtype: 'SimpleItemGrid',
            collapsible: true,
            store: this.getItemStore()
        }];

        this.callParent(arguments);
    },

    getItemStore: function() {
        return this.itemStore;
    }
});
like image 93
sra Avatar answered Nov 03 '22 00:11

sra


No, you can't do it in the way you've described. The reason is pretty simple, let's take this as an example:

Ext.define('MyClass', {
    someProp: this.foo(),

    foo: function(){
        return bar;
    }
});

Here, we call the define() method and we pass it an object as the configuration. As such, the whole object (including the call to foo()) is evaluated before it's even passed to define, so the class/method doesn't even exist at that point.

Even if you could do that, here's also the complication that foo is an instance method on the class, but the way you're attempting to call it is as though it's a static method.

So, the answer is, you'll need to use some kind of method to do so, initComponent is typically preferred over the constructor.

like image 39
Evan Trimboli Avatar answered Nov 03 '22 00:11

Evan Trimboli