/** * @class Ext.form.FormPanel * @extends Ext.panel.Panel *FormPanel provides a standard container for forms. It is essentially a standard {@link Ext.panel.Panel} which * automatically creates a {@link Ext.form.Basic BasicForm} for managing any {@link Ext.form.Field} * objects that are added as descendants of the panel. It also includes conveniences for configuring and * working with the BasicForm and the collection of Fields.
* *Layout
*By default, FormPanel is configured with {@link Ext.layout.AnchorLayout layout:'anchor'} for * the layout of its immediate child items. This can be changed to any of the supported container layouts. * The layout of sub-containers is configured in {@link Ext.lib.Container#layout the standard way}.
* *BasicForm
*Although not listed as configuration options of FormPanel, the FormPanel class accepts all * of the config options supported by the {@link Ext.form.Basic} class, and will pass them along to * the internal BasicForm when it is created.
*Note: If subclassing FormPanel, any configuration options for the BasicForm must be applied to * the initialConfig property of the FormPanel. Applying {@link Ext.form.Basic BasicForm} * configuration settings to this will not affect the BasicForm's configuration.
*The following events fired by the BasicForm will be re-fired by the FormPanel and can therefore be * listened for on the FormPanel itself:
** **
- {@link Ext.form.Basic#beforeaction beforeaction}
*- {@link Ext.form.Basic#actionfailed actionfailed}
*- {@link Ext.form.Basic#actioncomplete actioncomplete}
*- {@link Ext.form.Basic#validitychange validitychange}
*- {@link Ext.form.Basic#dirtychange dirtychange}
*Field Defaults
*The {@link #fieldDefaults} config option conveniently allows centralized configuration of default values * for all field-labelable added as descendants of the FormPanel. Any config option recognized by implementations * of {@link Ext.form.Labelable} may be included in this object. See the {@link #fieldDefaults} documentation * for details of how the defaults are applied.
* *Form Validation
*With the default configuration, form fields are validated on the fly while the user edits their values. * This can be controlled on a per-field basis (or via the {@link #fieldDefaults} config) with the field * config properties {@link Ext.form.Field#validateOnChange} and {@link Ext.form.BaseField#checkChangeEvents}, * and the FormPanel's config properties {@link #pollForChanges} and {@link #pollInterval}.
*Any component within the FormPanel can be configured with formBind: true. This will cause that * component to be automatically disabled when the form is invalid, and enabled when it is valid. This is most * commonly used for Button components to prevent submitting the form in an invalid state, but can be used on * any component type.
*For more information on form validation see the following:
** **
- {@link Ext.form.Field#validateOnChange}
*- {@link #pollForChanges} and {@link #pollInterval}
*- {@link Ext.form.VTypes}
*- {@link Ext.form.Basic#doAction BasicForm.doAction clientValidation notes}
*Form Submission
*By default, Ext Forms are submitted through Ajax, using {@link Ext.form.action.Action}. See the documentation for * {@link Ext.form.Basic}
* * @constructor * @param {Object} config Configuration options * @xtype form */ Ext.define('Ext.form.FormPanel', { extend:'Ext.panel.Panel', alias: 'widget.form', alternateClassName: 'Ext.FormPanel', requires: ['Ext.form.Basic', 'Ext.util.TaskRunner'], /** * @cfg {Object} fieldDefaults *If specified, the properties in this object are used as default config values for each * {@link Ext.form.Labelable} instance (e.g. {@link Ext.form.Field} or {@link Ext.form.FieldContainer}) * that is added as a descendant of this FormPanel. Corresponding values specified in an individual field's * own configuration, or from the {@link Ext.lib.Container#defaults defaults config} of its parent container, * will take precedence. See the documentation for {@link Ext.form.Labelable} to see what config * options may be specified in the fieldDefaults.
*Example:
**new Ext.form.FormPanel({ fieldDefaults: { labelAlign: 'left', labelWidth: 100 }, items: [{ xtype: 'fieldset', defaults: { labelAlign: 'top' }, items: [{ name: 'field1' }, { name: 'field2' }] }, { xtype: 'fieldset', items: [{ name: 'field3', labelWidth: 150 }, { name: 'field4' }] }] });
In this example, field1 and field2 will get labelAlign:'top' (from the fieldset's defaults) * and labelWidth:100 (from fieldDefaults), field3 and field4 will both get labelAlign:'left' (from * fieldDefaults and field3 will use the labelWidth:150 from its own config.
*/ /** * @cfg {Boolean} pollForChanges * If set to true, sets up an interval task (using the {@link #pollInterval}) in which the * panel's fields are repeatedly checked for changes in their values. This is in addition to the normal detection * each field does on its own input element, and is not needed in most cases. It does, however, provide a * means to absolutely guarantee detection of all changes including some edge cases in some browsers which * do not fire native events. Defaults to false. */ /** * @cfg {Number} pollInterval * Interval in milliseconds at which the form's fields are checked for value changes. Only used if * the {@link #pollForChanges} option is set to true. Defaults to 500 milliseconds. */ /** * @cfg {String} layout The {@link Ext.container.Container#layout} for the form panel's immediate child items. * Defaults to 'anchor'. */ layout: 'anchor', ariaRole: 'form', initComponent: function() { Ext.FormPanel.superclass.initComponent.call(this); this.relayEvents(this.form, [ 'beforeaction', 'actionfailed', 'actioncomplete', 'validitychange', 'dirtychange' ]); // Start polling if configured if (this.pollForChanges) { this.startPolling(this.pollInterval || 500); } }, initItems: function() { // Create the BasicForm this.form = this.createForm(); Ext.form.FormPanel.superclass.initItems.call(this); }, /** * @private */ createForm: function() { return new Ext.form.Basic(this, Ext.applyIf({listeners: {}}, this.initialConfig)); }, /** * Provides access to the {@link Ext.form.Basic Form} which this Panel contains. * @return {Ext.form.Basic} The {@link Ext.form.Basic Form} which this Panel contains. */ getForm: function() { return this.form; }, beforeDestroy: function() { this.stopPolling(); this.form.destroy(); Ext.FormPanel.superclass.beforeDestroy.call(this); }, /** * @private * Handle the addition of components to the FormPanel's child tree, copying the default field config * properties from the panel to individual fields as necessary. */ onSubCmpAdded: function(parent, child) { var me = this, minButtonWidth = me.minButtonWidth; function handleCmp(cmp) { if (cmp.isFieldLabelable) { cmp.applyFieldDefaults(me.fieldDefaults); } else if (cmp.isContainer) { cmp.items.each(handleCmp); } } handleCmp(child); Ext.form.FormPanel.superclass.onSubCmpAdded.apply(this, arguments); }, /** * This is a proxy for the underlying BasicForm's {@link Ext.form.Basic#load} call. * @param {Object} options The options to pass to the action (see {@link Ext.form.Basic#load} and * {@link Ext.form.Basic#doAction} for details) */ load: function(options) { this.form.load(options); }, /** * This is a proxy for the underlying BasicForm's {@link Ext.form.Basic#submit} call. * @param {Object} options The options to pass to the action (see {@link Ext.form.Basic#submit} and * {@link Ext.form.Basic#doAction} for details) */ submit: function(options) { this.form.submit(options); }, /** * Disable the FormPanel component and all the fields within it. * @param {Boolean} silent * Passing true, will supress the 'disable' event from being fired. */ disable: function(silent) { Ext.FormPanel.superclass.disable.call(this, silent); this.form.getFields().each(function(field) { field.disable(); }); }, /** * Enable the FormPanel component and all the fields within it. * @param {Boolean} silent * Passing false will supress the 'enable' event from being fired. */ enable: function(silent) { Ext.FormPanel.superclass.enable.call(this, silent); this.form.getFields().each(function(field) { field.enable(); }); }, /** * Start an interval task to continuously poll all the fields in the form for changes in their * values. This is normally started automatically by setting the {@link #pollForChanges} config. * @param {Number} interval The interval in milliseconds at which the check should run. */ startPolling: function(interval) { this.stopPolling(); var task = new Ext.util.TaskRunner(interval); task.start({ interval: 0, run: this.checkChanges, scope: this }); this.pollTask = task; }, /** * Stop a running interval task that was started by {@link #startPolling}. */ stopPolling: function() { var task = this.pollTask; if (task) { task.stopAll(); delete this.pollTask; } }, /** * Forces each field within the form panel to * {@link Ext.form.Field#checkChange check if its value has changed}. */ checkChanges: function() { this.form.getFields().each(function(field) { field.checkChange(); }); } });