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 * @docauthor Jason Johnston <jason@sencha.com>
18 * FormPanel provides a standard container for forms. It is essentially a standard {@link Ext.panel.Panel} which
19 * automatically creates a {@link Ext.form.Basic BasicForm} for managing any {@link Ext.form.field.Field}
20 * objects that are added as descendants of the panel. It also includes conveniences for configuring and
21 * working with the BasicForm and the collection of Fields.
25 * By default, FormPanel is configured with `{@link Ext.layout.container.Anchor layout:'anchor'}` for
26 * the layout of its immediate child items. This can be changed to any of the supported container layouts.
27 * The layout of sub-containers is configured in {@link Ext.container.Container#layout the standard way}.
31 * Although **not listed** as configuration options of FormPanel, the FormPanel class accepts all
32 * of the config options supported by the {@link Ext.form.Basic} class, and will pass them along to
33 * the internal BasicForm when it is created.
35 * **Note**: If subclassing FormPanel, any configuration options for the BasicForm must be applied to
36 * the `initialConfig` property of the FormPanel. Applying {@link Ext.form.Basic BasicForm}
37 * configuration settings to `this` will *not* affect the BasicForm's configuration.
39 * The following events fired by the BasicForm will be re-fired by the FormPanel and can therefore be
40 * listened for on the FormPanel itself:
42 * - {@link Ext.form.Basic#beforeaction beforeaction}
43 * - {@link Ext.form.Basic#actionfailed actionfailed}
44 * - {@link Ext.form.Basic#actioncomplete actioncomplete}
45 * - {@link Ext.form.Basic#validitychange validitychange}
46 * - {@link Ext.form.Basic#dirtychange dirtychange}
50 * The {@link #fieldDefaults} config option conveniently allows centralized configuration of default values
51 * for all fields added as descendants of the FormPanel. Any config option recognized by implementations
52 * of {@link Ext.form.Labelable} may be included in this object. See the {@link #fieldDefaults} documentation
53 * for details of how the defaults are applied.
57 * With the default configuration, form fields are validated on-the-fly while the user edits their values.
58 * This can be controlled on a per-field basis (or via the {@link #fieldDefaults} config) with the field
59 * config properties {@link Ext.form.field.Field#validateOnChange} and {@link Ext.form.field.Base#checkChangeEvents},
60 * and the FormPanel's config properties {@link #pollForChanges} and {@link #pollInterval}.
62 * Any component within the FormPanel can be configured with `formBind: true`. This will cause that
63 * component to be automatically disabled when the form is invalid, and enabled when it is valid. This is most
64 * commonly used for Button components to prevent submitting the form in an invalid state, but can be used on
67 * For more information on form validation see the following:
69 * - {@link Ext.form.field.Field#validateOnChange}
70 * - {@link #pollForChanges} and {@link #pollInterval}
71 * - {@link Ext.form.field.VTypes}
72 * - {@link Ext.form.Basic#doAction BasicForm.doAction clientValidation notes}
76 * By default, Ext Forms are submitted through Ajax, using {@link Ext.form.action.Action}. See the documentation for
77 * {@link Ext.form.Basic} for details.
82 * Ext.create('Ext.form.Panel', {
83 * title: 'Simple Form',
87 * // The form will submit an AJAX request to this URL when submitted
88 * url: 'save-form.php',
90 * // Fields will be arranged vertically, stretched to full width
97 * defaultType: 'textfield',
99 * fieldLabel: 'First Name',
103 * fieldLabel: 'Last Name',
108 * // Reset and Submit buttons
111 * handler: function() {
112 * this.up('form').getForm().reset();
116 * formBind: true, //only enabled once the form is valid
118 * handler: function() {
119 * var form = this.up('form').getForm();
120 * if (form.isValid()) {
122 * success: function(form, action) {
123 * Ext.Msg.alert('Success', action.result.msg);
125 * failure: function(form, action) {
126 * Ext.Msg.alert('Failed', action.result.msg);
132 * renderTo: Ext.getBody()
136 Ext.define('Ext.form.Panel', {
137 extend:'Ext.panel.Panel',
139 fieldAncestor: 'Ext.form.FieldAncestor'
141 alias: 'widget.form',
142 alternateClassName: ['Ext.FormPanel', 'Ext.form.FormPanel'],
143 requires: ['Ext.form.Basic', 'Ext.util.TaskRunner'],
146 * @cfg {Boolean} pollForChanges
147 * If set to `true`, sets up an interval task (using the {@link #pollInterval}) in which the
148 * panel's fields are repeatedly checked for changes in their values. This is in addition to the normal detection
149 * each field does on its own input element, and is not needed in most cases. It does, however, provide a
150 * means to absolutely guarantee detection of all changes including some edge cases in some browsers which
151 * do not fire native events. Defaults to `false`.
155 * @cfg {Number} pollInterval
156 * Interval in milliseconds at which the form's fields are checked for value changes. Only used if
157 * the {@link #pollForChanges} option is set to `true`. Defaults to 500 milliseconds.
161 * @cfg {String} layout
162 * The {@link Ext.container.Container#layout} for the form panel's immediate child items.
163 * Defaults to `'anchor'`.
169 initComponent: function() {
176 me.initFieldAncestor();
179 me.relayEvents(me.form, [
187 // Start polling if configured
188 if (me.pollForChanges) {
189 me.startPolling(me.pollInterval || 500);
193 initItems: function() {
194 // Create the BasicForm
197 me.form = me.createForm();
199 me.form.initialize();
205 createForm: function() {
206 return Ext.create('Ext.form.Basic', this, Ext.applyIf({listeners: {}}, this.initialConfig));
210 * Provides access to the {@link Ext.form.Basic Form} which this Panel contains.
211 * @return {Ext.form.Basic} The {@link Ext.form.Basic Form} which this Panel contains.
213 getForm: function() {
218 * Loads an {@link Ext.data.Model} into this form (internally just calls {@link Ext.form.Basic#loadRecord})
219 * See also {@link Ext.form.Basic#trackResetOnLoad trackResetOnLoad}.
220 * @param {Ext.data.Model} record The record to load
221 * @return {Ext.form.Basic} The Ext.form.Basic attached to this FormPanel
223 loadRecord: function(record) {
224 return this.getForm().loadRecord(record);
228 * Returns the currently loaded Ext.data.Model instance if one was loaded via {@link #loadRecord}.
229 * @return {Ext.data.Model} The loaded instance
231 getRecord: function() {
232 return this.getForm().getRecord();
236 * Convenience function for fetching the current value of each field in the form. This is the same as calling
237 * {@link Ext.form.Basic#getValues this.getForm().getValues()}
238 * @return {Object} The current form field values, keyed by field name
240 getValues: function() {
241 return this.getForm().getValues();
244 beforeDestroy: function() {
251 * This is a proxy for the underlying BasicForm's {@link Ext.form.Basic#load} call.
252 * @param {Object} options The options to pass to the action (see {@link Ext.form.Basic#load} and
253 * {@link Ext.form.Basic#doAction} for details)
255 load: function(options) {
256 this.form.load(options);
260 * This is a proxy for the underlying BasicForm's {@link Ext.form.Basic#submit} call.
261 * @param {Object} options The options to pass to the action (see {@link Ext.form.Basic#submit} and
262 * {@link Ext.form.Basic#doAction} for details)
264 submit: function(options) {
265 this.form.submit(options);
269 * Inherit docs, not using onDisable because it only gets fired
270 * when the component is rendered.
272 disable: function(silent) {
273 this.callParent(arguments);
274 this.form.getFields().each(function(field) {
280 * Inherit docs, not using onEnable because it only gets fired
281 * when the component is rendered.
283 enable: function(silent) {
284 this.callParent(arguments);
285 this.form.getFields().each(function(field) {
291 * Start an interval task to continuously poll all the fields in the form for changes in their
292 * values. This is normally started automatically by setting the {@link #pollForChanges} config.
293 * @param {Number} interval The interval in milliseconds at which the check should run.
295 startPolling: function(interval) {
297 var task = Ext.create('Ext.util.TaskRunner', interval);
300 run: this.checkChange,
303 this.pollTask = task;
307 * Stop a running interval task that was started by {@link #startPolling}.
309 stopPolling: function() {
310 var task = this.pollTask;
313 delete this.pollTask;
318 * Forces each field within the form panel to
319 * {@link Ext.form.field.Field#checkChange check if its value has changed}.
321 checkChange: function() {
322 this.form.getFields().each(function(field) {