0
votes

I have an app that uses a Tab layout with the same grid panel shared as an xtype widget between each form panel bound to each tab.

My Main tab layout is as follows:

Ext.define('cardioCatalogQT.view.main.Main', {
    extend: 'Ext.tab.Panel',
    xtype: 'main-view',
    controller: 'main-view',
    requires: [
        'cardioCatalogQT.view.main.MainController',
        'cardioCatalogQT.view.main.MainModel',
        'Ext.ux.form.ItemSelector',
        'Ext.tip.QuickTipManager',
        'Ext.layout.container.Card'
    ],

    style: 'background-color:#dfe8f5;',
    width: '100%',
    height: 400,

    layout: 'vbox',
    defaults: {
        bodyPadding: 5
    },
    items: [{
            title:'Main',
            region: 'south',
            xtype: 'form',
            itemId: 'Ajax',
            flex: 1,
            styleHtmlContent: true,
            items:[{
                xtype: 'image',
                src: 'resources/images/R3D3.png',
                height: 50,
                width: 280
            },{
                title: 'Ad Hoc Sandbox for Cohort Discovery'
            }] ,
            lbar:[{
                text: 'Initiate advanced request',
                xtype: 'button',

                handler: function(button){
                    var url = 'https://url_here';
                    //cardioCatalogQT.service.UtilityService.http_auth(button);
                    window.open(url);
                }
            }]
        },
        /*{
            xtype: 'resultsGrid'
            //disabled: true
        },*/
        /*{
            xtype: 'searchGrid'
            //disabled: true
        },*/
        {
            xtype: 'demographicGrid'
            //disabled: true
        },
        {
            xtype: 'vitalGrid'
            //disabled: true
        },
        {
            xtype: 'labGrid'
            //disabled: true
        },
        {
            xtype: 'diagnosisGrid'
            //disabled: true

        },
        {
            xtype: 'medicationGrid'
            //disabled: true
        },
        {
            xtype: 'procedureGrid'
            //disabled: true
        },
        {
            xtype: 'queryGrid'
            //disabled: true
        }
    ]
}); 

The individual tabs that share the same grid widget (specifically, demographicGrid, vitalGrid, labGrid, diagnosisGrid, procedureGrid and medicationGrid, each referenced by xtype in the main view) look like:

/**
 * Widget with template to render to Main view
 */

Ext.define('cardioCatalogQT.view.grid.DemographicGrid', {
    extend: 'Ext.form.Panel',
    alias: 'widget.demographicGrid',
    itemId: 'demographicGrid',
    store: 'Payload',

    requires: [
        'cardioCatalogQT.view.main.MainController'
    ],


    config: {
        variableHeights: false,
        title: 'Demographics',
        xtype: 'form',
        width: 200,
        bodyPadding: 10,
        defaults: {
            anchor: '100%',
            labelWidth: 100
        },


        // inline buttons
        dockedItems: [ {
            xtype: 'toolbar',
            height: 100,
            items: [{
                xtype: 'button',
                text: 'Constrain sex',
                itemId: 'showSex',
                hidden: false,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#sexValue').show();
                        button.up('grid').down('#hideSex').show();
                        button.up('grid').down('#showSex').hide();
                    }
                }
            }, {
                xtype: 'button',
                text: 'Hide sex constraint',
                itemId: 'hideSex',
                hidden: true,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#sexValue').hide();
                        button.up('grid').down('#sexValue').setValue('');
                        button.up('grid').down('#hideSex').hide();
                        button.up('grid').down('#showSex').show();
                    }
                }
            },{ // Sex
                xtype: 'combo',
                itemId: 'sexValue',
                queryMode: 'local',
                editable: false,
                value: 'eq',
                triggerAction: 'all',
                forceSelection: true,
                fieldLabel: 'Select sex',
                displayField: 'name',
                valueField: 'value',
                hidden: true,
                store: {
                    fields: ['name', 'value'],
                    data: [
                        {name: 'female', value: 'f'},
                        {name: 'male', value: 'm'}
                    ]
                }
            }, {
                xtype: 'button',
                text: 'Constrain age',
                itemId: 'showAge',
                hidden: false,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#ageComparator').show();
                        button.up('grid').down('#ageValue').show();
                        button.up('grid').down('#hideAge').show();
                        button.up('grid').down('#showAge').hide();
                    }
                }
            }, {
                xtype: 'button',
                text: 'Hide age',
                itemId: 'hideAge',
                hidden: true,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#ageComparator').hide();
                        button.up('grid').down('#ageValue').hide();
                        button.up('grid').down('#upperAgeValue').hide();
                        button.up('grid').down('#ageComparator').setValue('');
                        button.up('grid').down('#ageValue').setValue('');
                        button.up('grid').down('#upperAgeValue').setValue('');
                        button.up('grid').down('#hideAge').hide();
                        button.up('grid').down('#showAge').show();
                    }
                }
            }, { // Age
                xtype: 'combo',
                itemId: 'ageComparator',
                queryMode: 'local',
                editable: false,
                value: '',
                triggerAction: 'all',
                forceSelection: true,
                fieldLabel: 'Select age that is',
                displayField: 'name',
                valueField: 'value',
                hidden: true,
                store: {
                    fields: ['name', 'value'],
                    data: [
                        {name: '=', value: 'eq'},
                        {name: '<', value: 'lt'},
                        {name: '<=', value: 'le'},
                        {name: '>', value: 'gt'},
                        {name: '>=', value: 'ge'},
                        {name: 'between', value: 'bt'}
                    ]
                },

                listeners: {
                    change: function(combo, value) {
                        // use component query to  toggle the hidden state of upper value
                        if (value === 'bt') {
                            combo.up('grid').down('#upperAgeValue').show();
                        } else {
                            combo.up('grid').down('#upperAgeValue').hide();
                        }
                    }
                }
            },{
                xtype: 'numberfield',
                itemId: 'ageValue',
                fieldLabel: 'value of',
                value: '',
                hidden: true
            },{
                xtype: 'numberfield',
                itemId: 'upperAgeValue',
                fieldLabel: 'and',
                hidden: true
            },{
                xtype: 'button',
                text: 'Constrain race/ethnicity',
                itemId: 'showRace',
                hidden: false,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#raceValue').show();
                        button.up('grid').down('#hideRace').show();
                        button.up('grid').down('#showRace').hide();
                    }
                }
            }, {
                xtype: 'button',
                text: 'Hide race/ethnicity constraint',
                itemId: 'hideRace',
                hidden: true,
                listeners: {
                    click: function (button) {
                        button.up('grid').down('#raceValue').hide();
                        button.up('grid').down('#raceValue').setValue('');
                        button.up('grid').down('#hideRace').hide();
                        button.up('grid').down('#showRace').show();
                    }
                }
            },{ // Race
                xtype: 'combo',
                itemId: 'raceValue',
                queryMode: 'local',
                editable: false,
                value: 'eq',
                triggerAction: 'all',
                forceSelection: true,
                fieldLabel: 'Select race',
                displayField: 'name',
                valueField: 'value',
                hidden: true,
                store: {
                    fields: ['name', 'value'],
                    data: [
                        {name: 'female', value: 'f'},
                        {name: 'male', value: 'm'}
                    ]
                }
            },{
                //minWidth: 80,
                text: 'Add to search',
                xtype: 'button',
                itemId: 'searchClick',
                handler: 'onSubmitDemographics'
            }]
        },
            {
                xtype:'searchGrid'
            }
        ]

    }


});

The only difference between each of the form panels in the tabs are the item components. Each of these form panels references an xtype of 'searchGrid' and renders it like in the attached image:Tab rendered with searchGrid

The problem is that I have 6-instances of this same grid. This works for the most part, but it is causing some issues related to getting control of the checkboxes in my grid along with some bizarre grid store load behaviors, and honestly, keeping track of components using this anti-pattern is a PITA.

I would like to somehow have a single instance of my searchGrid in a lower vertical panel, while an upper vertical panel has the item components I need to change according to the requirements for each tab. An example of how the item controls vary is Different panel with different item components

My desired behavior is that when I click on a tab, the upper item components would take me to a different form panel, while the lower panel stay fixed on the search grid.

However, I currently have the searchGrid bound to each tab's form panel, since that is the only way I could get this to work.

The searchGrid grid panel looks like:

Ext.define('cardioCatalogQT.view.grid.Search', {
    extend: 'Ext.grid.Panel',

    xtype: 'framing-buttons',
    store: 'Payload',
    itemId: 'searchGrid',

    requires: [
        'cardioCatalogQT.view.main.MainController'
    ],

    columns: [
        {text: "ID", width: 50, sortable: true, dataIndex: 'id'},
        {text: "Type", width: 120, sortable: true, dataIndex: 'type'},
        {text: "Key", flex: 1, sortable: true, dataIndex: 'key'},
        {text: "Criteria", flex: 1, sortable: true, dataIndex: 'criteria'},
        {text: "DateOperator", flex: 1, sortable: true, dataIndex: 'dateComparatorSymbol'},
        {text: "When", flex: 1, sortable: true, dataIndex: 'dateValue'},
        {text: "Count", flex: 1, sortable: true, dataIndex: 'n'}
    ],
    columnLines: true,
    selModel: {
        type: 'checkboxmodel',
        listeners: {
            selectionchange: 'onSelectionChange'
        }
    },

    // When true, this view acts as the default listener scope for listeners declared within it.
    // For example the selectionModel's selectionchange listener resolves to this.
    defaultListenerScope: false,

    // This view acts as a reference holder for all components below it which have a reference config
    // For example the onSelectionChange listener accesses a button using its reference
    //referenceHolder: true,

    // inline buttons
    dockedItems: [{
        xtype: 'toolbar',
        dock: 'bottom',
        ui: 'footer',
        layout: {
            pack: 'center'
        }
    }, {
        xtype: 'toolbar',
        items: [{
            //reference: 'andButton',
            text: 'AND',
            itemId: 'andButton',
            tooltip: 'Add the selected criteria as AND',
            iconCls: 'and',
            disabled: true,
            handler: 'onCriterionAnd'
        },'-',{
            //reference: 'orButton',
            text: 'OR',
            itemId: 'orButton',
            tooltip: 'Add the selected criteria as OR',
            iconCls: 'or',
            disabled: true,
            handler: 'onCriterionOr'
        },'-',{
            //reference: 'notButton',
            text: 'NOT',
            itemId: 'notButton',
            tooltip: 'Add the selected criteria as NOT',
            iconCls: 'not',
            disabled: true,
            handler: 'onCriterionNot'
        },'-',{
            //reference: 'removeButton',  // The referenceHolder can access this button by this name
            text: 'Remove',
            itemId: 'removeButton',
            tooltip: 'Remove the selected item',
            iconCls: 'remove',
            disabled: true,
            handler: 'onCriterionRemove'
        },'-', { // SaveQuery
            //reference: 'SaveQuery',
            text: 'Save',
            itemId: 'saveQuery',
            tooltip: 'save the current filter',
            iconCls: 'save',
            disabled: true,
            handler: 'onFilterSave'
        }]
    }],

    height: 1000,
    frame: true,
    iconCls: 'icon-grid',
    alias: 'widget.searchGrid',
    title: 'Search',

    initComponent: function() {
        this.width = 750;
        this.callParent();
    }
});

I messed around with using a Vbox layout to get my desired behavior, but was rather unsuccessful. This does not seem like that uncommon of a use case to have an upper Vbox panel change to different form panels based on a Tab click, while the lower Vbox panel remains fixed. Any insight would be most welcome.

1
I would recommend to have a look at a border layout with two regions north and center.Alexander
I think I may have actually started out using this in the first place and due to a real estate issue instead went to tabs. I assume I would need to hide/unhide my item components to mimic the behavior of use of tabs in the north region, while my grid panel would be in the center region?horcle_buzz
Nope, no need to mimic anything, as can be seen in the answer I just posted.Alexander

1 Answers

1
votes

If I understand correctly, this small test of mine should do exactly what you want, using a border layout with regions north and center.

<!DOCTYPE HTML>
<html>
<head>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8">
    <link rel="stylesheet" href="ext-theme-gray.css">
    <title>Test app</title>
    <script type="text/javascript" src="ext-all-dev.js"></script>
    <script>
    Ext.onReady(function() {
        var Viewport = Ext.create('Ext.container.Viewport',{
            layout:'border',
            items:[{
                xtype:'tabpanel',
                region:'north',
                items:[{
                    xtype:'panel',
                    title:'A',
                    items:[{xtype:'button',text:'Clickme'}]
                },{
                    xtype:'panel',
                    title:'B',
                    items:[{xtype:'textfield'}]
                }]
            },{
                xtype:'gridpanel',
                title:'center',
                region:'center',
                columns:[{
                    dataIndex:'A',
                    text:'A'
                },{
                    dataIndex:'B',
                    text:'B'
                }]
            }]
        })
        Ext.create('Ext.app.Application',{
            name:'TestApp',
            autoCreateViewport: true,
            views:[
                Viewport
            ]
        });
    });
    </script>
</head>
<body>
</body>
</html>

PS: I used ExtJS 4.2.2, but it should work in other Ext versions as well.