2
votes

I just started with Extjs and I have few basic doubts.I have created a simple view(ScreenPropertiesPage) which has 1 select box and 1 custom view inside it. onchange of the select box value, view field is updated which is done in controller. I am done with creating view and controller which has listener for onchange select box value and updates associated view field.

But now the problem is : in my application I have to create 4 instances of ScreenPropertiesPage view and when onchange event is triggered from any views the textbox of 1st view is updated always. How to combine the event to specific view? What is the best procedure to combine controller and views and to reuse it(Even link to the documents from where I can learn controller view reusability is enough)? Any help is greatly appreciated.

Code skeleton for view:

Ext.define('Configurator.view.screenproperties.ScreenPropertiesPage', {
    extend: 'Ext.container.Container',
    alias: 'widget.screenpropertiespage',
    requires: [
        'Configurator.store.screenproperties.ScreenProperties'
    ],
    autoScroll: true,

    config: {
        overLayMode: false
    },
    initComponent: function () {
        var me = this;
        this.items = [{
            xtype: 'container',
            componentCls: 'screenComboSelectorPanel',
            layout: {
                type: 'hbox',
                align: 'center',
                pack: 'center'
            },
            items: [{
                xtype: 'combo',
                store: Ext.create(
                    'Configurator.store.screenproperties.ScreenProperties'
                ),
                itemId: 'screenSelector',
                margin: 3,
                width: 400,
                listConfig: {
                    maxHeight: 200
                },
                fieldLabel: 'Screen Name',
                disabledCls: 'disabledBtn',
                disabled: me.getOverLayMode(),
                queryMode: 'local',
                emptyText: '-SELECT-',
                valueField: 'screenName',
                displayField: 'screenName',
                forceSelection: true,
                selectOnTab: true,
                autoSelect: true,
                height: 25,
                tpl: Ext.create('Ext.XTemplate',
                    '<tpl for=".">',
                    '<div class="x-boundlist-item comboContainer "><div class="rowExpanedrTextArea " style="">{screenName}   </div>{[this.isExpandable(xkey,parent,values,xindex)]}</div>',
                    '</tpl>'
                ),
                displayTpl: Ext.create('Ext.XTemplate',
                    '<tpl for=".">',
                    '{screenName}',
                    '</tpl>'
                )
            }]
        }, {
            xtype: 'screenpropertieseditor',
            itemId: 'messagesEditor',
            margin: '25',
            header: true,
            frame: false,
            border: true,
            collectionName: 'messages',
            title: 'Messages'
        }]

        me.callParent(arguments);
    }
});

When user changes the value in combobox I want to update the screenpropertieseditor type view.

Controller for view :

Ext.define('Configurator.controller.ScreenProperties', {
    extend: 'Ext.app.Controller',

    refs: [{
        ref: 'screenPropertiesPage',
        selector: 'screenpropertiespage'
    }, {
        ref: 'screenSelector',
        selector: 'screenpropertiespage combobox[itemId=screenSelector]'
    }, {
        ref: 'screenPropertiesMessagesEditor',
        selector: 'screenpropertieseditor[itemId=messagesEditor]'
    }, {
        ref: 'screenPropertiesPage',
        selector: 'screenpropertiespage'
    }],

    init: function (application) {
        var me = this;
        this.control({
            'screenpropertiespage combobox[itemId=screenSelector]': {
                change: this.screenPropertiesPageStoreHandler
            }
        });
    },

    screenPropertiesPageStoreHandler: function (thisObj, eOpts) {
        var messagesEditor = this.getScreenPropertiesMessagesEditor();
        var screenSelector = this.getScreenSelector();
        var screenSelected = screenSelector.getValue();
        //Screen tile store first time loading handling
        if (screenSelected === undefined) {
            screenSelected = screenSelector.getStore().getAt(0).data.screenName;
        }

        var selectedRecord = screenSelector.getStore().findRecord(
            'screenName',
            screenSelected, 0, false, false, true);
        if (selectedRecord != undefined) {
            Ext.apply(messagesEditor, {
                'screenName': screenSelected
            });
            try {
                messagesEditor.bindStore(selectedRecord.messages());
            } catch (e) {}
        }
    }
});

ScreenPropertiesPage will hava lot more extra fields along with this. I have to create multiple instances of ScreenPropertiesPage. screenPropertiesPageStoreHandler method of Configurator.controller.ScreenProperties will be triggered whenever value changes in the combobox of any ScreenPropertiesPage view. But since my ref and selector in controller are not proper it always refers to the first ScreenPropertiesPage view.

1
@Tarabass I just edited the question to have code snippet. Let me know if the way I am doing it is completely wrong or if I have to change structure to achieve re usability. Thanks for your help.kumar

1 Answers

3
votes

You need to know that Controller in Extjs is singleton.

But you can force Controller in your case ScreenProperties to handle multiple instances of views. This is done by firing events from particular view instance to Controller to handle more complex logic.

Before i throw an example you need to be aware that using refs with handling multiple instance of the same view is wrong because it uses this code(it is just a wrapper): Ext.ComponentQuery.query('yourComponent')[0]; So from your view instances pool it gets first. So you need to get rid off refs in your controller since it does not work with multiple instance of the same view.

Alright, lets make this happen and implement good way to handle multiple instances of the same view/components.

In your view:

initComponent: function () {
        var me = this;
        this.items = [{
            xtype: 'container',
            componentCls: 'screenComboSelectorPanel',
            layout: {
                type: 'hbox',
                align: 'center',
                pack: 'center'
            },
            items: [{
                xtype: 'combo',
                store: Ext.create(
                    'Configurator.store.screenproperties.ScreenProperties'
                ),
                itemId: 'screenSelector',
                margin: 3,
                width: 400,
                listConfig: {
                    maxHeight: 200
                },
                fieldLabel: 'Screen Name',
                disabledCls: 'disabledBtn',
                disabled: me.getOverLayMode(),
                queryMode: 'local',
                emptyText: '-SELECT-',
                valueField: 'screenName',
                displayField: 'screenName',
                forceSelection: true,
                selectOnTab: true,
                autoSelect: true,
                height: 25,
                tpl: Ext.create('Ext.XTemplate',
                    '<tpl for=".">',
                    '<div class="x-boundlist-item comboContainer "><div class="rowExpanedrTextArea " style="">{screenName}   </div>{[this.isExpandable(xkey,parent,values,xindex)]}</div>',
                    '</tpl>'
                ),
                displayTpl: Ext.create('Ext.XTemplate',
                    '<tpl for=".">',
                    '{screenName}',
                    '</tpl>'
                ),
                listeners: {
                    change: function (cmp, newValue, oldValue) {
                       this.fireEvent('onCustomChange',cmp,newValue, oldValue)
                    },
                    scope: this
                }
            }]
        }

In your Controller - ScreenProperties you need to listen on this event and handle particular instance of component in view:

init: function (application) {
    var me = this;
    this.listen({
        // We are using Controller event domain here
        controller: {
            // This selector matches any originating Controller
            '*': {      
                onCustomChange: 'onCustonChangeHandler'
            }
        }
    });
},
onCustonChangeHandler: function(componentInstance, newValue, oldValue) {
    //Your complex logic here.
    //componentInstance is the instance of actual component in particular view
}

In this way you can handle multiple instances of the same view with one controller since every particular component that is created in your view is passed by event.