Upgrade to ExtJS 4.0.0 - Released 04/26/2011
[extjs.git] / src / container / Container.js
1 /**
2  * @class Ext.container.Container
3  * @extends Ext.container.AbstractContainer
4  * <p>Base class for any {@link Ext.Component} that may contain other Components. Containers handle the
5  * basic behavior of containing items, namely adding, inserting and removing items.</p>
6  *
7  * <p>The most commonly used Container classes are {@link Ext.panel.Panel}, {@link Ext.window.Window} and {@link Ext.tab.Panel}.
8  * If you do not need the capabilities offered by the aforementioned classes you can create a lightweight
9  * Container to be encapsulated by an HTML element to your specifications by using the
10  * <code><b>{@link Ext.Component#autoEl autoEl}</b></code> config option.</p>
11  *
12  * {@img Ext.Container/Ext.Container.png Ext.Container component} 
13  * <p>The code below illustrates how to explicitly create a Container:<pre><code>
14 // explicitly create a Container
15 Ext.create('Ext.container.Container', {
16     layout: {
17         type: 'hbox'
18     },
19     width: 400,
20     renderTo: Ext.getBody(),
21     border: 1,
22     style: {borderColor:'#000000', borderStyle:'solid', borderWidth:'1px'},
23     defaults: {
24         labelWidth: 80,
25         // implicitly create Container by specifying xtype
26         xtype: 'datefield',
27         flex: 1,
28         style: {
29             padding: '10px'
30         }
31     },
32     items: [{
33         xtype: 'datefield',
34         name: 'startDate',
35         fieldLabel: 'Start date'
36     },{
37         xtype: 'datefield',
38         name: 'endDate',
39         fieldLabel: 'End date'
40     }]
41 });
42 </code></pre></p>
43  *
44  * <p><u><b>Layout</b></u></p>
45  * <p>Container classes delegate the rendering of child Components to a layout
46  * manager class which must be configured into the Container using the
47  * <code><b>{@link #layout}</b></code> configuration property.</p>
48  * <p>When either specifying child <code>{@link #items}</code> of a Container,
49  * or dynamically {@link #add adding} Components to a Container, remember to
50  * consider how you wish the Container to arrange those child elements, and
51  * whether those child elements need to be sized using one of Ext's built-in
52  * <b><code>{@link #layout}</code></b> schemes. By default, Containers use the
53  * {@link Ext.layout.container.Auto Auto} scheme which only
54  * renders child components, appending them one after the other inside the
55  * Container, and <b>does not apply any sizing</b> at all.</p>
56  * <p>A common mistake is when a developer neglects to specify a
57  * <b><code>{@link #layout}</code></b> (e.g. widgets like GridPanels or
58  * TreePanels are added to Containers for which no <code><b>{@link #layout}</b></code>
59  * has been specified). If a Container is left to use the default
60  * {Ext.layout.container.Auto Auto} scheme, none of its
61  * child components will be resized, or changed in any way when the Container
62  * is resized.</p>
63  * <p>Certain layout managers allow dynamic addition of child components.
64  * Those that do include {@link Ext.layout.container.Card},
65  * {@link Ext.layout.container.Anchor}, {@link Ext.layout.container.VBox}, {@link Ext.layout.container.HBox}, and
66  * {@link Ext.layout.container.Table}. For example:<pre><code>
67 //  Create the GridPanel.
68 var myNewGrid = new Ext.grid.Panel({
69     store: myStore,
70     headers: myHeaders,
71     title: 'Results', // the title becomes the title of the tab
72 });
73
74 myTabPanel.add(myNewGrid); // {@link Ext.tab.Panel} implicitly uses {@link Ext.layout.container.Card Card}
75 myTabPanel.{@link Ext.tab.Panel#setActiveTab setActiveTab}(myNewGrid);
76  * </code></pre></p>
77  * <p>The example above adds a newly created GridPanel to a TabPanel. Note that
78  * a TabPanel uses {@link Ext.layout.container.Card} as its layout manager which
79  * means all its child items are sized to {@link Ext.layout.container.Fit fit}
80  * exactly into its client area.
81  * <p><b><u>Overnesting is a common problem</u></b>.
82  * An example of overnesting occurs when a GridPanel is added to a TabPanel
83  * by wrapping the GridPanel <i>inside</i> a wrapping Panel (that has no
84  * <code><b>{@link #layout}</b></code> specified) and then add that wrapping Panel
85  * to the TabPanel. The point to realize is that a GridPanel <b>is</b> a
86  * Component which can be added directly to a Container. If the wrapping Panel
87  * has no <code><b>{@link #layout}</b></code> configuration, then the overnested
88  * GridPanel will not be sized as expected.<p>
89  *
90  * <p><u><b>Adding via remote configuration</b></u></p>
91  *
92  * <p>A server side script can be used to add Components which are generated dynamically on the server.
93  * An example of adding a GridPanel to a TabPanel where the GridPanel is generated by the server
94  * based on certain parameters:
95  * </p><pre><code>
96 // execute an Ajax request to invoke server side script:
97 Ext.Ajax.request({
98     url: 'gen-invoice-grid.php',
99     // send additional parameters to instruct server script
100     params: {
101         startDate: Ext.getCmp('start-date').getValue(),
102         endDate: Ext.getCmp('end-date').getValue()
103     },
104     // process the response object to add it to the TabPanel:
105     success: function(xhr) {
106         var newComponent = eval(xhr.responseText); // see discussion below
107         myTabPanel.add(newComponent); // add the component to the TabPanel
108         myTabPanel.setActiveTab(newComponent);
109     },
110     failure: function() {
111         Ext.Msg.alert("Grid create failed", "Server communication failure");
112     }
113 });
114 </code></pre>
115  * <p>The server script needs to return a JSON representation of a configuration object, which, when decoded
116  * will return a config object with an {@link Ext.Component#xtype xtype}. The server might return the following
117  * JSON:</p><pre><code>
118 {
119     "xtype": 'grid',
120     "title": 'Invoice Report',
121     "store": {
122         "model": 'Invoice',
123         "proxy": {
124             "type": 'ajax',
125             "url": 'get-invoice-data.php',
126             "reader": {
127                 "type": 'json'
128                 "record": 'transaction',
129                 "idProperty": 'id',
130                 "totalRecords": 'total'
131             })
132         },
133         "autoLoad": {
134             "params": {
135                 "startDate": '01/01/2008',
136                 "endDate": '01/31/2008'
137             }
138         }
139     },
140     "headers": [
141         {"header": "Customer", "width": 250, "dataIndex": 'customer', "sortable": true},
142         {"header": "Invoice Number", "width": 120, "dataIndex": 'invNo', "sortable": true},
143         {"header": "Invoice Date", "width": 100, "dataIndex": 'date', "renderer": Ext.util.Format.dateRenderer('M d, y'), "sortable": true},
144         {"header": "Value", "width": 120, "dataIndex": 'value', "renderer": 'usMoney', "sortable": true}
145     ]
146 }
147 </code></pre>
148  * <p>When the above code fragment is passed through the <code>eval</code> function in the success handler
149  * of the Ajax request, the result will be a config object which, when added to a Container, will cause instantiation
150  * of a GridPanel. <b>Be sure that the Container is configured with a layout which sizes and positions the child items to your requirements.</b></p>
151  * <p>Note: since the code above is <i>generated</i> by a server script, the <code>autoLoad</code> params for
152  * the Store, the user's preferred date format, the metadata to allow generation of the Model layout, and the ColumnModel
153  * can all be generated into the code since these are all known on the server.</p>
154  *
155  * @xtype container
156  */
157 Ext.define('Ext.container.Container', {
158     extend: 'Ext.container.AbstractContainer',
159     alias: 'widget.container',
160     alternateClassName: 'Ext.Container',
161
162     /**
163      * Return the immediate child Component in which the passed element is located.
164      * @param el The element to test.
165      * @return {Component} The child item which contains the passed element.
166      */
167     getChildByElement: function(el) {
168         var item,
169             itemEl,
170             i = 0,
171             it = this.items.items,
172             ln = it.length;
173
174         el = Ext.getDom(el);
175         for (; i < ln; i++) {
176             item = it[i];
177             itemEl = item.getEl();
178             if ((itemEl.dom === el) || itemEl.contains(el)) {
179                 return item;
180             }
181         }
182         return null;
183     }
184 });