Base class for any 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 Ext.Panel, Ext.Window and 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
autoEl
config option. This is a useful technique when creating
embedded column layouts inside 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
layout
configuration property.
When either specifying child items
of a Container,
or dynamically 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
layout
schemes. By default, Containers use the
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
layout
(e.g. widgets like GridPanels or
TreePanels are added to Containers for which no layout
has been specified). If a Container is left to use the default
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 Ext.layout.CardLayout, Ext.layout.AnchorLayout, Ext.layout.FormLayout, and 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); // Ext.TabPanel implicitly uses CardLayout
myTabPanel.setActiveTab(myNewGrid);
The example above adds a newly created GridPanel to a TabPanel. Note that a TabPanel uses Ext.layout.CardLayout as its layout manager which means all its child items are sized to 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
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 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 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.