0
votes

I have a container with two panels as it items. I want both panels to be collapsible (at the same time no one or only one panel can be collapsed) and if any panel is collapsed other panel should take all remaining space. Also I want to be able to resize both panels with Ext.resizer.Splitter.

I have tried different combinations of (h/v)box / border layout, but none of them works correctly.

It seems like Ext.layout.container.Accordion is what I need but, as I can see, it doest work with Ext.resizer.Splitter out of the box.

Check this fiddle

Also, I want to be able to collapse both panels with single Ext.resizer.Splitter, but as I can see its not available out of the box and I have to override it. Am I right?

I'm using ExtJS version 4.2.1.

3
So you would like something like an accordion but with the ability to collapse all items? - scebotari66
@scebotari66 Yes, something like that, but with Ext.resizer.Splitter. Actually, I almost forgot about accordion layout! Maybe I can integrate it with splitter in some way... - Sergey Novikov
If this question seems incorrect to you for any reason, then please write why. Dont just downvote. - Sergey Novikov

3 Answers

1
votes

Does this help?

Ext.application({
name: 'Fiddle',

launch: function () {

    Ext.create('Ext.Container', {
        height: 500,
        renderTo: Ext.getBody(),
        width: 500,
        layout: {
            type: 'vbox',
            align: 'stretch'
        },

        items: [{
            xtype: 'panel',
            reference: 'panel1',
            title: 'Top panel',
            collapsible: true,  // To allow collapse
            flex: 1,
            bodyStyle: 'background: #dadada',
            listeners: {
                collapse: function(){
                    this.up().down("[reference='panel2']").expand();
                }
            }
        }, 
        {
            xtype: 'splitter' 
        },
        {
            xtype: 'panel',
            reference: 'panel2',
            title: 'Bottom panel',
            collapsible: true,  // To allow collapse
            flex: 1,
            bodyStyle: 'background: #999',
            listeners: {
                collapse: function(){
                    this.up().down("[reference='panel1']").expand();
                }
            }
        }]

    });
}});

Here vbox is used to set the panels vertically (the flex property tells them how much space to take from each other). The collapsible property set to true makes them collapsible. Then each panel has an event that expands the sibling panel when the target panel collapses. With this, at least one panel is always expanded and you can resize them with the splitter!


Edit 1:

The previous code sample isn't generic and does not react as expected if we set panels with animCollapse: false. A generic solution would look like the following:

// Our extended container
Ext.define('MyVboxContainer', {
    extend: 'Ext.Container',

    layout: {
        type: 'vbox',
        align: 'stretch'
    },

    // We do the setup on initiating the component
    initComponent: function () {
        var me = this;
        var panelCount = 0;

        // For each child component
        this.items.forEach(function (comp) {

            // If the component is a panel
            if (comp.xtype === 'panel') {

                // We add an unique ref
                comp.reference = 'panel' + panelCount;

                // Increment the total number of panels
                panelCount++

                // And listeners for beforecollapse, collapse and expand
                comp.listeners = {
                    // On collpase, we track the last collapsed panel
                    'collapse': function () {
                        me.closedCount++;

                        me.lastClosed = this.reference;
                    },

                    // On expand we decrement the total number of panels collapsed
                    'expand': function () {
                        me.closedCount--;
                    },

                    // If this is the last panel being collapsed,
                    // we expand the previous collapsed panel
                    // Note: this cannot be done on the expand event
                    // if the panel has animCollapse: false
                    'beforecollapse': function () {
                        if (me.closedCount + 1 == me.totalPanels) {
                            me.down("[reference='" + me.lastClosed + "']").expand();
                        }
                    }
                };
            }
        });

        this.totalPanels = panelCount; // total number of panels
        this.lastClosed = null; // Last collapsed panel
        this.closedCount = 0; // How many panels we have closed

        console.log("Total panels are: " + this.totalPanels)

        this.callParent();
    }
});

Ext.application({
    name: 'Fiddle',

    launch: function () {

        Ext.create('MyVboxContainer', {
            height: 500,
            width: 500,
            renderTo: Ext.getBody(),

            items: [{
                xtype: 'panel',
                animCollapse: false,
                title: 'Top panel',
                collapsible: true, // To allow collapse
                flex: 1,
                bodyStyle: 'background: #dadada'
            }, {
                xtype: 'splitter'
            }, {
                xtype: 'panel',
                title: 'Middle panel',
                animCollapse: false,
                collapsible: true, // To allow collapse
                flex: 1,
                bodyStyle: 'background: #999'
            }, {
                xtype: 'splitter'
            }, {
                xtype: 'panel',
                title: 'Bottom panel',
                animCollapse: false,
                collapsible: true, // To allow collapse
                flex: 1,
                bodyStyle: 'background: #999'
            }]
        });
    }
});

Here we create an extended container that uses vbox layout to set the panels vertically. On initComponent, this container setups the existing children panels to always keep the penultimate collapsed panel expanded. You should modify the algorithm to suit your needs.

Sidenote: it isn't ideal to set variables on the view container. These variables should be moved into a controller.

1
votes

I wrote component, based on Ext.resizer.Splitter code. Its allow to collapse both panels with single splitter.

Solution is abit raw, you can check it in this fiddle.

0
votes

In ExtJs have spliter.

You can user inside your container. Here I have created an demo with collapsible panel.

Hope it will help you to solve your problem. Sencha Fiddle

Ext.create('Ext.container.Container', {
     height: 300,
     layout: {
         type: 'vbox',
         align: 'stretch'
     },
     width: 400,
     renderTo: Ext.getBody(),
     border: 1,
     items: [{
         xtype: 'panel',
         collapsible: true,
         title: 'First Panel',
         flex: 1
     }, {
         xtype: 'splitter',
         height: 20
     }, {
         xtype: 'panel',
         collapsible: true,
         flex: 1,
         maintainFlex: true,
         title: 'Second Panel'
     }]
 });