/** * @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
* * @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; } });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.