3 This file is part of Ext JS 4
5 Copyright (c) 2011 Sencha Inc
7 Contact: http://www.sencha.com/contact
9 GNU General Public License Usage
10 This file may be used under the terms of the GNU General Public License version 3.0 as published by the Free Software Foundation and appearing in the file LICENSE included in the packaging of this file. Please review the following information to ensure the GNU General Public License version 3.0 requirements will be met: http://www.gnu.org/copyleft/gpl.html.
12 If you are unsure which license is appropriate for your use, please contact the sales department at http://www.sencha.com/contact.
16 * @class Ext.form.FieldContainer
17 * @extends Ext.container.Container
19 FieldContainer is a derivation of {@link Ext.container.Container Container} that implements the
20 {@link Ext.form.Labelable Labelable} mixin. This allows it to be configured so that it is rendered with
21 a {@link #fieldLabel field label} and optional {@link #msgTarget error message} around its sub-items.
22 This is useful for arranging a group of fields or other components within a single item in a form, so
23 that it lines up nicely with other fields. A common use is for grouping a set of related fields under
24 a single label in a form.
26 The container's configured {@link #items} will be layed out within the field body area according to the
27 configured {@link #layout} type. The default layout is `'autocontainer'`.
29 Like regular fields, FieldContainer can inherit its decoration configuration from the
30 {@link Ext.form.Panel#fieldDefaults fieldDefaults} of an enclosing FormPanel. In addition,
31 FieldContainer itself can pass {@link #fieldDefaults} to any {@link Ext.form.Labelable fields}
32 it may itself contain.
34 If you are grouping a set of {@link Ext.form.field.Checkbox Checkbox} or {@link Ext.form.field.Radio Radio}
35 fields in a single labeled container, consider using a {@link Ext.form.CheckboxGroup}
36 or {@link Ext.form.RadioGroup} instead as they are specialized for handling those types.
37 {@img Ext.form.FieldContainer/Ext.form.FieldContainer1.png Ext.form.FieldContainer component}
40 Ext.create('Ext.form.Panel', {
41 title: 'FieldContainer Example',
46 xtype: 'fieldcontainer',
47 fieldLabel: 'Last Three Jobs',
50 // The body area will contain three text fields, arranged
51 // horizontally, separated by draggable splitters.
68 renderTo: Ext.getBody()
71 __Usage of {@link #fieldDefaults}:__
72 {@img Ext.form.FieldContainer/Ext.form.FieldContainer2.png Ext.form.FieldContainer component}
74 Ext.create('Ext.form.Panel', {
75 title: 'FieldContainer Example',
80 xtype: 'fieldcontainer',
81 fieldLabel: 'Your Name',
83 defaultType: 'textfield',
85 // Arrange fields vertically, stretched to full width
91 // These config values will be applied to both sub-fields, except
92 // for Last Name which will use its own msgTarget.
99 fieldLabel: 'First Name',
102 fieldLabel: 'Last Name',
107 renderTo: Ext.getBody()
112 * @docauthor Jason Johnston <jason@sencha.com>
114 Ext.define('Ext.form.FieldContainer', {
115 extend: 'Ext.container.Container',
117 labelable: 'Ext.form.Labelable',
118 fieldAncestor: 'Ext.form.FieldAncestor'
120 alias: 'widget.fieldcontainer',
122 componentLayout: 'field',
125 * @cfg {Boolean} combineLabels
126 * If set to true, and there is no defined {@link #fieldLabel}, the field container will automatically
127 * generate its label by combining the labels of all the fields it contains. Defaults to false.
129 combineLabels: false,
132 * @cfg {String} labelConnector
133 * The string to use when joining the labels of individual sub-fields, when {@link #combineLabels} is
134 * set to true. Defaults to ', '.
136 labelConnector: ', ',
139 * @cfg {Boolean} combineErrors
140 * If set to true, the field container will automatically combine and display the validation errors from
141 * all the fields it contains as a single error on the container, according to the configured
142 * {@link #msgTarget}. Defaults to false.
144 combineErrors: false,
146 maskOnDisable: false,
148 initComponent: function() {
150 onSubCmpAddOrRemove = me.onSubCmpAddOrRemove;
154 me.initFieldAncestor();
160 * @protected Called when a {@link Ext.form.Labelable} instance is added to the container's subtree.
161 * @param {Ext.form.Labelable} labelable The instance that was added
163 onLabelableAdded: function(labelable) {
165 me.mixins.fieldAncestor.onLabelableAdded.call(this, labelable);
170 * @protected Called when a {@link Ext.form.Labelable} instance is removed from the container's subtree.
171 * @param {Ext.form.Labelable} labelable The instance that was removed
173 onLabelableRemoved: function(labelable) {
175 me.mixins.fieldAncestor.onLabelableRemoved.call(this, labelable);
179 onRender: function() {
181 renderSelectors = me.renderSelectors,
182 applyIf = Ext.applyIf;
184 applyIf(renderSelectors, me.getLabelableSelectors());
186 me.callParent(arguments);
189 initRenderTpl: function() {
191 if (!me.hasOwnProperty('renderTpl')) {
192 me.renderTpl = me.getTpl('labelableRenderTpl');
194 return me.callParent();
197 initRenderData: function() {
198 return Ext.applyIf(this.callParent(), this.getLabelableRenderData());
202 * Returns the combined field label if {@link #combineLabels} is set to true and if there is no
203 * set {@link #fieldLabel}. Otherwise returns the fieldLabel like normal. You can also override
204 * this method to provide a custom generated label.
206 getFieldLabel: function() {
207 var label = this.fieldLabel || '';
208 if (!label && this.combineLabels) {
209 label = Ext.Array.map(this.query('[isFieldLabelable]'), function(field) {
210 return field.getFieldLabel();
211 }).join(this.labelConnector);
217 * @private Updates the content of the labelEl if it is rendered
219 updateLabel: function() {
223 label.update(me.getFieldLabel());
229 * @private Fired when the error message of any field within the container changes, and updates the
230 * combined error message to match.
232 onFieldErrorChange: function(field, activeError) {
233 if (this.combineErrors) {
235 oldError = me.getActiveError(),
236 invalidFields = Ext.Array.filter(me.query('[isFormField]'), function(field) {
237 return field.hasActiveError();
239 newErrors = me.getCombinedErrors(invalidFields);
242 me.setActiveErrors(newErrors);
244 me.unsetActiveError();
247 if (oldError !== me.getActiveError()) {
248 me.doComponentLayout();
254 * Takes an Array of invalid {@link Ext.form.field.Field} objects and builds a combined list of error
255 * messages from them. Defaults to prepending each message by the field name and a colon. This
256 * can be overridden to provide custom combined error message handling, for instance changing
257 * the format of each message or sorting the array (it is sorted in order of appearance by default).
258 * @param {Array} invalidFields An Array of the sub-fields which are currently invalid.
259 * @return {Array} The combined list of error messages
261 getCombinedErrors: function(invalidFields) {
262 var forEach = Ext.Array.forEach,
264 forEach(invalidFields, function(field) {
265 forEach(field.getActiveErrors(), function(error) {
266 var label = field.getFieldLabel();
267 errors.push((label ? label + ': ' : '') + error);
273 getTargetEl: function() {
274 return this.bodyEl || this.callParent();