/** * @class Ext.Container * @extends Ext.BoxComponent *

Base class for any {@link Ext.BoxComponent} that may contain other Components. Containers handle the * basic behavior of containing items, namely adding, inserting and removing items.

* *

The most commonly used Container classes are {@link Ext.Panel}, {@link Ext.Window} and {@link Ext.TabPanel}. * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight * Container to be encapsulated by an HTML element to your specifications by using the * {@link Ext.Component#autoEl autoEl} config option. This is a useful technique when creating * embedded {@link Ext.layout.ColumnLayout column} layouts inside {@link Ext.form.FormPanel FormPanels} * for example.

* *

The code below illustrates both how to explicitly create a Container, and how to implicitly * create one using the 'container' xtype:


// explicitly create a Container
var embeddedColumns = new Ext.Container({
    autoEl: 'div',  // This is the default
    layout: 'column',
    defaults: {
        // implicitly create Container by specifying xtype
        xtype: 'container',
        autoEl: 'div', // This is the default.
        layout: 'form',
        columnWidth: 0.5,
        style: {
            padding: '10px'
        }
    },
//  The two items below will be Ext.Containers, each encapsulated by a <DIV> element.
    items: [{
        items: {
            xtype: 'datefield',
            name: 'startDate',
            fieldLabel: 'Start date'
        }
    }, {
        items: {
            xtype: 'datefield',
            name: 'endDate',
            fieldLabel: 'End date'
        }
    }]
});

* *

Layout

*

Container classes delegate the rendering of child Components to a layout * manager class which must be configured into the Container using the * {@link #layout} configuration property.

*

When either specifying child {@link #items} of a Container, * or dynamically {@link #add adding} Components to a Container, remember to * consider how you wish the Container to arrange those child elements, and * whether those child elements need to be sized using one of Ext's built-in * {@link #layout} schemes. By default, Containers use the * {@link Ext.layout.ContainerLayout ContainerLayout} scheme which only * renders child components, appending them one after the other inside the * Container, and does not apply any sizing at all.

*

A common mistake is when a developer neglects to specify a * {@link #layout} (e.g. widgets like GridPanels or * TreePanels are added to Containers for which no {@link #layout} * has been specified). If a Container is left to use the default * {@link Ext.layout.ContainerLayout ContainerLayout} scheme, none of its * child components will be resized, or changed in any way when the Container * is resized.

*

Certain layout managers allow dynamic addition of child components. * Those that do include {@link Ext.layout.CardLayout}, * {@link Ext.layout.AnchorLayout}, {@link Ext.layout.FormLayout}, and * {@link Ext.layout.TableLayout}. For example:


//  Create the GridPanel.
var myNewGrid = new Ext.grid.GridPanel({
    store: myStore,
    columns: myColumnModel,
    title: 'Results', // the title becomes the title of the tab
});

myTabPanel.add(myNewGrid); // {@link Ext.TabPanel} implicitly uses {@link Ext.layout.CardLayout CardLayout}
myTabPanel.{@link Ext.TabPanel#setActiveTab setActiveTab}(myNewGrid);
 * 

*

The example above adds a newly created GridPanel to a TabPanel. Note that * a TabPanel uses {@link Ext.layout.CardLayout} as its layout manager which * means all its child items are sized to {@link Ext.layout.FitLayout fit} * exactly into its client area. *

Overnesting is a common problem. * An example of overnesting occurs when a GridPanel is added to a TabPanel * by wrapping the GridPanel inside a wrapping Panel (that has no * {@link #layout} specified) and then add that wrapping Panel * to the TabPanel. The point to realize is that a GridPanel is a * Component which can be added directly to a Container. If the wrapping Panel * has no {@link #layout} configuration, then the overnested * GridPanel will not be sized as expected.

* *

Adding via remote configuration

* *

A server side script can be used to add Components which are generated dynamically on the server. * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server * based on certain parameters: *


// execute an Ajax request to invoke server side script:
Ext.Ajax.request({
    url: 'gen-invoice-grid.php',
    // send additional parameters to instruct server script
    params: {
        startDate: Ext.getCmp('start-date').getValue(),
        endDate: Ext.getCmp('end-date').getValue()
    },
    // process the response object to add it to the TabPanel:
    success: function(xhr) {
        var newComponent = eval(xhr.responseText); // see discussion below
        myTabPanel.add(newComponent); // add the component to the TabPanel
        myTabPanel.setActiveTab(newComponent);
    },
    failure: function() {
        Ext.Msg.alert("Grid create failed", "Server communication failure");
    }
});
*

The server script needs to return an executable Javascript statement which, when processed * using eval(), will return either a config object with an {@link Ext.Component#xtype xtype}, * or an instantiated Component. The server might return this for example:


(function() {
    function formatDate(value){
        return value ? value.dateFormat('M d, Y') : '';
    };

    var store = new Ext.data.Store({
        url: 'get-invoice-data.php',
        baseParams: {
            startDate: '01/01/2008',
            endDate: '01/31/2008'
        },
        reader: new Ext.data.JsonReader({
            record: 'transaction',
            idProperty: 'id',
            totalRecords: 'total'
        }, [
           'customer',
           'invNo',
           {name: 'date', type: 'date', dateFormat: 'm/d/Y'},
           {name: 'value', type: 'float'}
        ])
    });

    var grid = new Ext.grid.GridPanel({
        title: 'Invoice Report',
        bbar: new Ext.PagingToolbar(store),
        store: store,
        columns: [
            {header: "Customer", width: 250, dataIndex: 'customer', sortable: true},
            {header: "Invoice Number", width: 120, dataIndex: 'invNo', sortable: true},
            {header: "Invoice Date", width: 100, dataIndex: 'date', renderer: formatDate, sortable: true},
            {header: "Value", width: 120, dataIndex: 'value', renderer: 'usMoney', sortable: true}
        ],
    });
    store.load();
    return grid;  // return instantiated component
})();
*

When the above code fragment is passed through the eval function in the success handler * of the Ajax request, the code is executed by the Javascript processor, and the anonymous function * runs, and returns the instantiated grid component.

*

Note: since the code above is generated by a server script, the baseParams for * the Store, the metadata to allow generation of the Record layout, and the ColumnModel * can all be generated into the code since these are all known on the server.

* * @xtype container */ Ext.define('Ext.container.Container', { extend: 'Ext.AbstractContainer', alias: 'widget.container', alternateClassName: 'Ext.Container',
/** * Return the immediate child Component in which the passed element is located. * @param el The element to test. * @return {Component} The child item which contains the passed element. */ getChildByElement: function(el) { var item, itemEl, i = 0, it = this.items.items, ln = it.length; el = Ext.getDom(el); for (; i < ln; i++) { item = it[i]; itemEl = item.getEl(); if ((itemEl.dom === el) || itemEl.contains(el)) { return item; } } return null; } });