Upgrade to ExtJS 4.0.2 - Released 06/09/2011
[extjs.git] / docs / source / Basic.html
1 <!DOCTYPE html>
2 <html>
3 <head>
4   <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
5   <title>The source code</title>
6   <link href="../prettify/prettify.css" type="text/css" rel="stylesheet" />
7   <script type="text/javascript" src="../prettify/prettify.js"></script>
8   <style type="text/css">
9     .highlight { display: block; background-color: #ddd; }
10   </style>
11   <script type="text/javascript">
12     function highlight() {
13       document.getElementById(location.hash.replace(/#/, "")).className = "highlight";
14     }
15   </script>
16 </head>
17 <body onload="prettyPrint(); highlight();">
18   <pre class="prettyprint lang-js"><span id='Ext-form-Basic'>/**
19 </span> * @class Ext.form.Basic
20  * @extends Ext.util.Observable
21  * 
22  * Provides input field management, validation, submission, and form loading services for the collection
23  * of {@link Ext.form.field.Field Field} instances within a {@link Ext.container.Container}. It is recommended
24  * that you use a {@link Ext.form.Panel} as the form container, as that has logic to automatically
25  * hook up an instance of {@link Ext.form.Basic} (plus other conveniences related to field configuration.)
26  * 
27  * ## Form Actions
28  * 
29  * The Basic class delegates the handling of form loads and submits to instances of {@link Ext.form.action.Action}.
30  * See the various Action implementations for specific details of each one's functionality, as well as the
31  * documentation for {@link #doAction} which details the configuration options that can be specified in
32  * each action call.
33  * 
34  * The default submit Action is {@link Ext.form.action.Submit}, which uses an Ajax request to submit the
35  * form's values to a configured URL. To enable normal browser submission of an Ext form, use the
36  * {@link #standardSubmit} config option.
37  * 
38  * Note: File uploads are not performed using normal 'Ajax' techniques; see the description for
39  * {@link #hasUpload} for details.
40  * 
41  * ## Example usage:
42  * 
43  *     Ext.create('Ext.form.Panel', {
44  *         title: 'Basic Form',
45  *         renderTo: Ext.getBody(),
46  *         bodyPadding: 5,
47  *         width: 350,
48  * 
49  *         // Any configuration items here will be automatically passed along to
50  *         // the Ext.form.Basic instance when it gets created.
51  * 
52  *         // The form will submit an AJAX request to this URL when submitted
53  *         url: 'save-form.php',
54  * 
55  *         items: [{
56  *             fieldLabel: 'Field',
57  *             name: 'theField'
58  *         }],
59  * 
60  *         buttons: [{
61  *             text: 'Submit',
62  *             handler: function() {
63  *                 // The getForm() method returns the Ext.form.Basic instance:
64  *                 var form = this.up('form').getForm();
65  *                 if (form.isValid()) {
66  *                     // Submit the Ajax request and handle the response
67  *                     form.submit({
68  *                         success: function(form, action) {
69  *                            Ext.Msg.alert('Success', action.result.msg);
70  *                         },
71  *                         failure: function(form, action) {
72  *                             Ext.Msg.alert('Failed', action.result.msg);
73  *                         }
74  *                     });
75  *                 }
76  *             }
77  *         }]
78  *     });
79  * 
80  * @docauthor Jason Johnston &lt;jason@sencha.com&gt;
81  */
82 Ext.define('Ext.form.Basic', {
83     extend: 'Ext.util.Observable',
84     alternateClassName: 'Ext.form.BasicForm',
85     requires: ['Ext.util.MixedCollection', 'Ext.form.action.Load', 'Ext.form.action.Submit',
86                'Ext.window.MessageBox', 'Ext.data.Errors', 'Ext.util.DelayedTask'],
87
88 <span id='Ext-form-Basic-method-constructor'>    /**
89 </span>     * Creates new form.
90      * @param {Ext.container.Container} owner The component that is the container for the form, usually a {@link Ext.form.Panel}
91      * @param {Object} config Configuration options. These are normally specified in the config to the
92      * {@link Ext.form.Panel} constructor, which passes them along to the BasicForm automatically.
93      */
94     constructor: function(owner, config) {
95         var me = this,
96             onItemAddOrRemove = me.onItemAddOrRemove;
97
98 <span id='Ext-form-Basic-property-owner'>        /**
99 </span>         * @property owner
100          * @type Ext.container.Container
101          * The container component to which this BasicForm is attached.
102          */
103         me.owner = owner;
104
105         // Listen for addition/removal of fields in the owner container
106         me.mon(owner, {
107             add: onItemAddOrRemove,
108             remove: onItemAddOrRemove,
109             scope: me
110         });
111
112         Ext.apply(me, config);
113
114         // Normalize the paramOrder to an Array
115         if (Ext.isString(me.paramOrder)) {
116             me.paramOrder = me.paramOrder.split(/[\s,|]/);
117         }
118
119         me.checkValidityTask = Ext.create('Ext.util.DelayedTask', me.checkValidity, me);
120
121         me.addEvents(
122 <span id='Ext-form-Basic-event-beforeaction'>            /**
123 </span>             * @event beforeaction
124              * Fires before any action is performed. Return false to cancel the action.
125              * @param {Ext.form.Basic} this
126              * @param {Ext.form.action.Action} action The {@link Ext.form.action.Action} to be performed
127              */
128             'beforeaction',
129 <span id='Ext-form-Basic-event-actionfailed'>            /**
130 </span>             * @event actionfailed
131              * Fires when an action fails.
132              * @param {Ext.form.Basic} this
133              * @param {Ext.form.action.Action} action The {@link Ext.form.action.Action} that failed
134              */
135             'actionfailed',
136 <span id='Ext-form-Basic-event-actioncomplete'>            /**
137 </span>             * @event actioncomplete
138              * Fires when an action is completed.
139              * @param {Ext.form.Basic} this
140              * @param {Ext.form.action.Action} action The {@link Ext.form.action.Action} that completed
141              */
142             'actioncomplete',
143 <span id='Ext-form-Basic-event-validitychange'>            /**
144 </span>             * @event validitychange
145              * Fires when the validity of the entire form changes.
146              * @param {Ext.form.Basic} this
147              * @param {Boolean} valid &lt;tt&gt;true&lt;/tt&gt; if the form is now valid, &lt;tt&gt;false&lt;/tt&gt; if it is now invalid.
148              */
149             'validitychange',
150 <span id='Ext-form-Basic-event-dirtychange'>            /**
151 </span>             * @event dirtychange
152              * Fires when the dirty state of the entire form changes.
153              * @param {Ext.form.Basic} this
154              * @param {Boolean} dirty &lt;tt&gt;true&lt;/tt&gt; if the form is now dirty, &lt;tt&gt;false&lt;/tt&gt; if it is no longer dirty.
155              */
156             'dirtychange'
157         );
158         me.callParent();
159     },
160
161 <span id='Ext-form-Basic-method-initialize'>    /**
162 </span>     * Do any post constructor initialization
163      * @private
164      */
165     initialize: function(){
166         this.initialized = true;
167         this.onValidityChange(!this.hasInvalidField());
168     },
169
170 <span id='Ext-form-Basic-cfg-method'>    /**
171 </span>     * @cfg {String} method
172      * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
173      */
174 <span id='Ext-form-Basic-cfg-reader'>    /**
175 </span>     * @cfg {Ext.data.reader.Reader} reader
176      * An Ext.data.DataReader (e.g. {@link Ext.data.reader.Xml}) to be used to read
177      * data when executing 'load' actions. This is optional as there is built-in
178      * support for processing JSON responses.
179      */
180 <span id='Ext-form-Basic-cfg-errorReader'>    /**
181 </span>     * @cfg {Ext.data.reader.Reader} errorReader
182      * &lt;p&gt;An Ext.data.DataReader (e.g. {@link Ext.data.reader.Xml}) to be used to
183      * read field error messages returned from 'submit' actions. This is optional
184      * as there is built-in support for processing JSON responses.&lt;/p&gt;
185      * &lt;p&gt;The Records which provide messages for the invalid Fields must use the
186      * Field name (or id) as the Record ID, and must contain a field called 'msg'
187      * which contains the error message.&lt;/p&gt;
188      * &lt;p&gt;The errorReader does not have to be a full-blown implementation of a
189      * Reader. It simply needs to implement a &lt;tt&gt;read(xhr)&lt;/tt&gt; function
190      * which returns an Array of Records in an object with the following
191      * structure:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
192 {
193     records: recordArray
194 }
195 &lt;/code&gt;&lt;/pre&gt;
196      */
197
198 <span id='Ext-form-Basic-cfg-url'>    /**
199 </span>     * @cfg {String} url
200      * The URL to use for form actions if one isn't supplied in the
201      * {@link #doAction doAction} options.
202      */
203
204 <span id='Ext-form-Basic-cfg-baseParams'>    /**
205 </span>     * @cfg {Object} baseParams
206      * &lt;p&gt;Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.&lt;/p&gt;
207      * &lt;p&gt;Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode Ext.Object.toQueryString}.&lt;/p&gt;
208      */
209
210 <span id='Ext-form-Basic-cfg-timeout'>    /**
211 </span>     * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
212      */
213     timeout: 30,
214
215 <span id='Ext-form-Basic-cfg-api'>    /**
216 </span>     * @cfg {Object} api (Optional) If specified, load and submit actions will be handled
217      * with {@link Ext.form.action.DirectLoad} and {@link Ext.form.action.DirectLoad}.
218      * Methods which have been imported by {@link Ext.direct.Manager} can be specified here to load and submit
219      * forms.
220      * Such as the following:&lt;pre&gt;&lt;code&gt;
221 api: {
222     load: App.ss.MyProfile.load,
223     submit: App.ss.MyProfile.submit
224 }
225 &lt;/code&gt;&lt;/pre&gt;
226      * &lt;p&gt;Load actions can use &lt;code&gt;{@link #paramOrder}&lt;/code&gt; or &lt;code&gt;{@link #paramsAsHash}&lt;/code&gt;
227      * to customize how the load method is invoked.
228      * Submit actions will always use a standard form submit. The &lt;tt&gt;formHandler&lt;/tt&gt; configuration must
229      * be set on the associated server-side method which has been imported by {@link Ext.direct.Manager}.&lt;/p&gt;
230      */
231
232 <span id='Ext-form-Basic-cfg-paramOrder'>    /**
233 </span>     * @cfg {Array/String} paramOrder &lt;p&gt;A list of params to be executed server side.
234      * Defaults to &lt;tt&gt;undefined&lt;/tt&gt;. Only used for the &lt;code&gt;{@link #api}&lt;/code&gt;
235      * &lt;code&gt;load&lt;/code&gt; configuration.&lt;/p&gt;
236      * &lt;p&gt;Specify the params in the order in which they must be executed on the
237      * server-side as either (1) an Array of String values, or (2) a String of params
238      * delimited by either whitespace, comma, or pipe. For example,
239      * any of the following would be acceptable:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
240 paramOrder: ['param1','param2','param3']
241 paramOrder: 'param1 param2 param3'
242 paramOrder: 'param1,param2,param3'
243 paramOrder: 'param1|param2|param'
244      &lt;/code&gt;&lt;/pre&gt;
245      */
246
247 <span id='Ext-form-Basic-cfg-paramsAsHash'>    /**
248 </span>     * @cfg {Boolean} paramsAsHash Only used for the &lt;code&gt;{@link #api}&lt;/code&gt;
249      * &lt;code&gt;load&lt;/code&gt; configuration. If &lt;tt&gt;true&lt;/tt&gt;, parameters will be sent as a
250      * single hash collection of named arguments (defaults to &lt;tt&gt;false&lt;/tt&gt;). Providing a
251      * &lt;tt&gt;{@link #paramOrder}&lt;/tt&gt; nullifies this configuration.
252      */
253     paramsAsHash: false,
254
255 <span id='Ext-form-Basic-cfg-waitTitle'>    /**
256 </span>     * @cfg {String} waitTitle
257      * The default title to show for the waiting message box (defaults to &lt;tt&gt;'Please Wait...'&lt;/tt&gt;)
258      */
259     waitTitle: 'Please Wait...',
260
261 <span id='Ext-form-Basic-cfg-trackResetOnLoad'>    /**
262 </span>     * @cfg {Boolean} trackResetOnLoad If set to &lt;tt&gt;true&lt;/tt&gt;, {@link #reset}() resets to the last loaded
263      * or {@link #setValues}() data instead of when the form was first created.  Defaults to &lt;tt&gt;false&lt;/tt&gt;.
264      */
265     trackResetOnLoad: false,
266
267 <span id='Ext-form-Basic-cfg-standardSubmit'>    /**
268 </span>     * @cfg {Boolean} standardSubmit
269      * &lt;p&gt;If set to &lt;tt&gt;true&lt;/tt&gt;, a standard HTML form submit is used instead
270      * of a XHR (Ajax) style form submission. Defaults to &lt;tt&gt;false&lt;/tt&gt;. All of
271      * the field values, plus any additional params configured via {@link #baseParams}
272      * and/or the &lt;code&gt;options&lt;/code&gt; to {@link #submit}, will be included in the
273      * values submitted in the form.&lt;/p&gt;
274      */
275
276 <span id='Ext-form-Basic-cfg-waitMsgTarget'>    /**
277 </span>     * @cfg {Mixed} waitMsgTarget
278      * By default wait messages are displayed with Ext.MessageBox.wait. You can target a specific
279      * element by passing it or its id or mask the form itself by passing in true. Defaults to &lt;tt&gt;undefined&lt;/tt&gt;.
280      */
281
282
283     // Private
284     wasDirty: false,
285
286
287 <span id='Ext-form-Basic-method-destroy'>    /**
288 </span>     * Destroys this object.
289      */
290     destroy: function() {
291         this.clearListeners();
292         this.checkValidityTask.cancel();
293     },
294
295 <span id='Ext-form-Basic-method-onItemAddOrRemove'>    /**
296 </span>     * @private
297      * Handle addition or removal of descendant items. Invalidates the cached list of fields
298      * so that {@link #getFields} will do a fresh query next time it is called. Also adds listeners
299      * for state change events on added fields, and tracks components with formBind=true.
300      */
301     onItemAddOrRemove: function(parent, child) {
302         var me = this,
303             isAdding = !!child.ownerCt,
304             isContainer = child.isContainer;
305
306         function handleField(field) {
307             // Listen for state change events on fields
308             me[isAdding ? 'mon' : 'mun'](field, {
309                 validitychange: me.checkValidity,
310                 dirtychange: me.checkDirty,
311                 scope: me,
312                 buffer: 100 //batch up sequential calls to avoid excessive full-form validation
313             });
314             // Flush the cached list of fields
315             delete me._fields;
316         }
317
318         if (child.isFormField) {
319             handleField(child);
320         }
321         else if (isContainer) {
322             // Walk down
323             Ext.Array.forEach(child.query('[isFormField]'), handleField);
324         }
325
326         // Flush the cached list of formBind components
327         delete this._boundItems;
328
329         // Check form bind, but only after initial add. Batch it to prevent excessive validation
330         // calls when many fields are being added at once.
331         if (me.initialized) {
332             me.checkValidityTask.delay(10);
333         }
334     },
335
336 <span id='Ext-form-Basic-method-getFields'>    /**
337 </span>     * Return all the {@link Ext.form.field.Field} components in the owner container.
338      * @return {Ext.util.MixedCollection} Collection of the Field objects
339      */
340     getFields: function() {
341         var fields = this._fields;
342         if (!fields) {
343             fields = this._fields = Ext.create('Ext.util.MixedCollection');
344             fields.addAll(this.owner.query('[isFormField]'));
345         }
346         return fields;
347     },
348
349     getBoundItems: function() {
350         var boundItems = this._boundItems;
351         if (!boundItems) {
352             boundItems = this._boundItems = Ext.create('Ext.util.MixedCollection');
353             boundItems.addAll(this.owner.query('[formBind]'));
354         }
355         return boundItems;
356     },
357
358 <span id='Ext-form-Basic-method-hasInvalidField'>    /**
359 </span>     * Returns true if the form contains any invalid fields. No fields will be marked as invalid
360      * as a result of calling this; to trigger marking of fields use {@link #isValid} instead.
361      */
362     hasInvalidField: function() {
363         return !!this.getFields().findBy(function(field) {
364             var preventMark = field.preventMark,
365                 isValid;
366             field.preventMark = true;
367             isValid = field.isValid();
368             field.preventMark = preventMark;
369             return !isValid;
370         });
371     },
372
373 <span id='Ext-form-Basic-method-isValid'>    /**
374 </span>     * Returns true if client-side validation on the form is successful. Any invalid fields will be
375      * marked as invalid. If you only want to determine overall form validity without marking anything,
376      * use {@link #hasInvalidField} instead.
377      * @return Boolean
378      */
379     isValid: function() {
380         var me = this,
381             invalid;
382         me.batchLayouts(function() {
383             invalid = me.getFields().filterBy(function(field) {
384                 return !field.validate();
385             });
386         });
387         return invalid.length &lt; 1;
388     },
389
390 <span id='Ext-form-Basic-method-checkValidity'>    /**
391 </span>     * Check whether the validity of the entire form has changed since it was last checked, and
392      * if so fire the {@link #validitychange validitychange} event. This is automatically invoked
393      * when an individual field's validity changes.
394      */
395     checkValidity: function() {
396         var me = this,
397             valid = !me.hasInvalidField();
398         if (valid !== me.wasValid) {
399             me.onValidityChange(valid);
400             me.fireEvent('validitychange', me, valid);
401             me.wasValid = valid;
402         }
403     },
404
405 <span id='Ext-form-Basic-method-onValidityChange'>    /**
406 </span>     * @private
407      * Handle changes in the form's validity. If there are any sub components with
408      * formBind=true then they are enabled/disabled based on the new validity.
409      * @param {Boolean} valid
410      */
411     onValidityChange: function(valid) {
412         var boundItems = this.getBoundItems();
413         if (boundItems) {
414             boundItems.each(function(cmp) {
415                 if (cmp.disabled === valid) {
416                     cmp.setDisabled(!valid);
417                 }
418             });
419         }
420     },
421
422 <span id='Ext-form-Basic-method-isDirty'>    /**
423 </span>     * &lt;p&gt;Returns true if any fields in this form have changed from their original values.&lt;/p&gt;
424      * &lt;p&gt;Note that if this BasicForm was configured with {@link #trackResetOnLoad} then the
425      * Fields' &lt;em&gt;original values&lt;/em&gt; are updated when the values are loaded by {@link #setValues}
426      * or {@link #loadRecord}.&lt;/p&gt;
427      * @return Boolean
428      */
429     isDirty: function() {
430         return !!this.getFields().findBy(function(f) {
431             return f.isDirty();
432         });
433     },
434
435 <span id='Ext-form-Basic-method-checkDirty'>    /**
436 </span>     * Check whether the dirty state of the entire form has changed since it was last checked, and
437      * if so fire the {@link #dirtychange dirtychange} event. This is automatically invoked
438      * when an individual field's dirty state changes.
439      */
440     checkDirty: function() {
441         var dirty = this.isDirty();
442         if (dirty !== this.wasDirty) {
443             this.fireEvent('dirtychange', this, dirty);
444             this.wasDirty = dirty;
445         }
446     },
447
448 <span id='Ext-form-Basic-method-hasUpload'>    /**
449 </span>     * &lt;p&gt;Returns true if the form contains a file upload field. This is used to determine the
450      * method for submitting the form: File uploads are not performed using normal 'Ajax' techniques,
451      * that is they are &lt;b&gt;not&lt;/b&gt; performed using XMLHttpRequests. Instead a hidden &lt;tt&gt;&amp;lt;form&gt;&lt;/tt&gt;
452      * element containing all the fields is created temporarily and submitted with its
453      * &lt;a href=&quot;http://www.w3.org/TR/REC-html40/present/frames.html#adef-target&quot;&gt;target&lt;/a&gt; set to refer
454      * to a dynamically generated, hidden &lt;tt&gt;&amp;lt;iframe&gt;&lt;/tt&gt; which is inserted into the document
455      * but removed after the return data has been gathered.&lt;/p&gt;
456      * &lt;p&gt;The server response is parsed by the browser to create the document for the IFRAME. If the
457      * server is using JSON to send the return object, then the
458      * &lt;a href=&quot;http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.17&quot;&gt;Content-Type&lt;/a&gt; header
459      * must be set to &quot;text/html&quot; in order to tell the browser to insert the text unchanged into the document body.&lt;/p&gt;
460      * &lt;p&gt;Characters which are significant to an HTML parser must be sent as HTML entities, so encode
461      * &quot;&amp;lt;&quot; as &quot;&amp;amp;lt;&quot;, &quot;&amp;amp;&quot; as &quot;&amp;amp;amp;&quot; etc.&lt;/p&gt;
462      * &lt;p&gt;The response text is retrieved from the document, and a fake XMLHttpRequest object
463      * is created containing a &lt;tt&gt;responseText&lt;/tt&gt; property in order to conform to the
464      * requirements of event handlers and callbacks.&lt;/p&gt;
465      * &lt;p&gt;Be aware that file upload packets are sent with the content type &lt;a href=&quot;http://www.faqs.org/rfcs/rfc2388.html&quot;&gt;multipart/form&lt;/a&gt;
466      * and some server technologies (notably JEE) may require some custom processing in order to
467      * retrieve parameter names and parameter values from the packet content.&lt;/p&gt;
468      * @return Boolean
469      */
470     hasUpload: function() {
471         return !!this.getFields().findBy(function(f) {
472             return f.isFileUpload();
473         });
474     },
475
476 <span id='Ext-form-Basic-method-doAction'>    /**
477 </span>     * Performs a predefined action (an implementation of {@link Ext.form.action.Action})
478      * to perform application-specific processing.
479      * @param {String/Ext.form.action.Action} action The name of the predefined action type,
480      * or instance of {@link Ext.form.action.Action} to perform.
481      * @param {Object} options (optional) The options to pass to the {@link Ext.form.action.Action}
482      * that will get created, if the &lt;tt&gt;action&lt;/tt&gt; argument is a String.
483      * &lt;p&gt;All of the config options listed below are supported by both the
484      * {@link Ext.form.action.Submit submit} and {@link Ext.form.action.Load load}
485      * actions unless otherwise noted (custom actions could also accept
486      * other config options):&lt;/p&gt;&lt;ul&gt;
487      *
488      * &lt;li&gt;&lt;b&gt;url&lt;/b&gt; : String&lt;div class=&quot;sub-desc&quot;&gt;The url for the action (defaults
489      * to the form's {@link #url}.)&lt;/div&gt;&lt;/li&gt;
490      *
491      * &lt;li&gt;&lt;b&gt;method&lt;/b&gt; : String&lt;div class=&quot;sub-desc&quot;&gt;The form method to use (defaults
492      * to the form's method, or POST if not defined)&lt;/div&gt;&lt;/li&gt;
493      *
494      * &lt;li&gt;&lt;b&gt;params&lt;/b&gt; : String/Object&lt;div class=&quot;sub-desc&quot;&gt;&lt;p&gt;The params to pass
495      * (defaults to the form's baseParams, or none if not defined)&lt;/p&gt;
496      * &lt;p&gt;Parameters are encoded as standard HTTP parameters using {@link Ext#urlEncode Ext.Object.toQueryString}.&lt;/p&gt;&lt;/div&gt;&lt;/li&gt;
497      *
498      * &lt;li&gt;&lt;b&gt;headers&lt;/b&gt; : Object&lt;div class=&quot;sub-desc&quot;&gt;Request headers to set for the action.&lt;/div&gt;&lt;/li&gt;
499      *
500      * &lt;li&gt;&lt;b&gt;success&lt;/b&gt; : Function&lt;div class=&quot;sub-desc&quot;&gt;The callback that will
501      * be invoked after a successful response (see top of
502      * {@link Ext.form.action.Submit submit} and {@link Ext.form.action.Load load}
503      * for a description of what constitutes a successful response).
504      * The function is passed the following parameters:&lt;ul&gt;
505      * &lt;li&gt;&lt;tt&gt;form&lt;/tt&gt; : The {@link Ext.form.Basic} that requested the action.&lt;/li&gt;
506      * &lt;li&gt;&lt;tt&gt;action&lt;/tt&gt; : The {@link Ext.form.action.Action Action} object which performed the operation.
507      * &lt;div class=&quot;sub-desc&quot;&gt;The action object contains these properties of interest:&lt;ul&gt;
508      * &lt;li&gt;&lt;tt&gt;{@link Ext.form.action.Action#response response}&lt;/tt&gt;&lt;/li&gt;
509      * &lt;li&gt;&lt;tt&gt;{@link Ext.form.action.Action#result result}&lt;/tt&gt; : interrogate for custom postprocessing&lt;/li&gt;
510      * &lt;li&gt;&lt;tt&gt;{@link Ext.form.action.Action#type type}&lt;/tt&gt;&lt;/li&gt;
511      * &lt;/ul&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/li&gt;
512      *
513      * &lt;li&gt;&lt;b&gt;failure&lt;/b&gt; : Function&lt;div class=&quot;sub-desc&quot;&gt;The callback that will be invoked after a
514      * failed transaction attempt. The function is passed the following parameters:&lt;ul&gt;
515      * &lt;li&gt;&lt;tt&gt;form&lt;/tt&gt; : The {@link Ext.form.Basic} that requested the action.&lt;/li&gt;
516      * &lt;li&gt;&lt;tt&gt;action&lt;/tt&gt; : The {@link Ext.form.action.Action Action} object which performed the operation.
517      * &lt;div class=&quot;sub-desc&quot;&gt;The action object contains these properties of interest:&lt;ul&gt;
518      * &lt;li&gt;&lt;tt&gt;{@link Ext.form.action.Action#failureType failureType}&lt;/tt&gt;&lt;/li&gt;
519      * &lt;li&gt;&lt;tt&gt;{@link Ext.form.action.Action#response response}&lt;/tt&gt;&lt;/li&gt;
520      * &lt;li&gt;&lt;tt&gt;{@link Ext.form.action.Action#result result}&lt;/tt&gt; : interrogate for custom postprocessing&lt;/li&gt;
521      * &lt;li&gt;&lt;tt&gt;{@link Ext.form.action.Action#type type}&lt;/tt&gt;&lt;/li&gt;
522      * &lt;/ul&gt;&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;&lt;/div&gt;&lt;/li&gt;
523      *
524      * &lt;li&gt;&lt;b&gt;scope&lt;/b&gt; : Object&lt;div class=&quot;sub-desc&quot;&gt;The scope in which to call the
525      * callback functions (The &lt;tt&gt;this&lt;/tt&gt; reference for the callback functions).&lt;/div&gt;&lt;/li&gt;
526      *
527      * &lt;li&gt;&lt;b&gt;clientValidation&lt;/b&gt; : Boolean&lt;div class=&quot;sub-desc&quot;&gt;Submit Action only.
528      * Determines whether a Form's fields are validated in a final call to
529      * {@link Ext.form.Basic#isValid isValid} prior to submission. Set to &lt;tt&gt;false&lt;/tt&gt;
530      * to prevent this. If undefined, pre-submission field validation is performed.&lt;/div&gt;&lt;/li&gt;&lt;/ul&gt;
531      *
532      * @return {Ext.form.Basic} this
533      */
534     doAction: function(action, options) {
535         if (Ext.isString(action)) {
536             action = Ext.ClassManager.instantiateByAlias('formaction.' + action, Ext.apply({}, options, {form: this}));
537         }
538         if (this.fireEvent('beforeaction', this, action) !== false) {
539             this.beforeAction(action);
540             Ext.defer(action.run, 100, action);
541         }
542         return this;
543     },
544
545 <span id='Ext-form-Basic-method-submit'>    /**
546 </span>     * Shortcut to {@link #doAction do} a {@link Ext.form.action.Submit submit action}. This will use the
547      * {@link Ext.form.action.Submit AJAX submit action} by default. If the {@link #standardsubmit} config is
548      * enabled it will use a standard form element to submit, or if the {@link #api} config is present it will
549      * use the {@link Ext.form.action.DirectLoad Ext.direct.Direct submit action}.
550      * @param {Object} options The options to pass to the action (see {@link #doAction} for details).&lt;br&gt;
551      * &lt;p&gt;The following code:&lt;/p&gt;&lt;pre&gt;&lt;code&gt;
552 myFormPanel.getForm().submit({
553     clientValidation: true,
554     url: 'updateConsignment.php',
555     params: {
556         newStatus: 'delivered'
557     },
558     success: function(form, action) {
559        Ext.Msg.alert('Success', action.result.msg);
560     },
561     failure: function(form, action) {
562         switch (action.failureType) {
563             case Ext.form.action.Action.CLIENT_INVALID:
564                 Ext.Msg.alert('Failure', 'Form fields may not be submitted with invalid values');
565                 break;
566             case Ext.form.action.Action.CONNECT_FAILURE:
567                 Ext.Msg.alert('Failure', 'Ajax communication failed');
568                 break;
569             case Ext.form.action.Action.SERVER_INVALID:
570                Ext.Msg.alert('Failure', action.result.msg);
571        }
572     }
573 });
574 &lt;/code&gt;&lt;/pre&gt;
575      * would process the following server response for a successful submission:&lt;pre&gt;&lt;code&gt;
576 {
577     &quot;success&quot;:true, // note this is Boolean, not string
578     &quot;msg&quot;:&quot;Consignment updated&quot;
579 }
580 &lt;/code&gt;&lt;/pre&gt;
581      * and the following server response for a failed submission:&lt;pre&gt;&lt;code&gt;
582 {
583     &quot;success&quot;:false, // note this is Boolean, not string
584     &quot;msg&quot;:&quot;You do not have permission to perform this operation&quot;
585 }
586 &lt;/code&gt;&lt;/pre&gt;
587      * @return {Ext.form.Basic} this
588      */
589     submit: function(options) {
590         return this.doAction(this.standardSubmit ? 'standardsubmit' : this.api ? 'directsubmit' : 'submit', options);
591     },
592
593 <span id='Ext-form-Basic-method-load'>    /**
594 </span>     * Shortcut to {@link #doAction do} a {@link Ext.form.action.Load load action}.
595      * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
596      * @return {Ext.form.Basic} this
597      */
598     load: function(options) {
599         return this.doAction(this.api ? 'directload' : 'load', options);
600     },
601
602 <span id='Ext-form-Basic-method-updateRecord'>    /**
603 </span>     * Persists the values in this form into the passed {@link Ext.data.Model} object in a beginEdit/endEdit block.
604      * @param {Ext.data.Record} record The record to edit
605      * @return {Ext.form.Basic} this
606      */
607     updateRecord: function(record) {
608         var fields = record.fields,
609             values = this.getFieldValues(),
610             name,
611             obj = {};
612
613         fields.each(function(f) {
614             name = f.name;
615             if (name in values) {
616                 obj[name] = values[name];
617             }
618         });
619
620         record.beginEdit();
621         record.set(obj);
622         record.endEdit();
623
624         return this;
625     },
626
627 <span id='Ext-form-Basic-method-loadRecord'>    /**
628 </span>     * Loads an {@link Ext.data.Model} into this form by calling {@link #setValues} with the
629      * {@link Ext.data.Model#data record data}.
630      * See also {@link #trackResetOnLoad}.
631      * @param {Ext.data.Model} record The record to load
632      * @return {Ext.form.Basic} this
633      */
634     loadRecord: function(record) {
635         this._record = record;
636         return this.setValues(record.data);
637     },
638     
639 <span id='Ext-form-Basic-method-getRecord'>    /**
640 </span>     * Returns the last Ext.data.Model instance that was loaded via {@link #loadRecord}
641      * @return {Ext.data.Model} The record
642      */
643     getRecord: function() {
644         return this._record;
645     },
646
647 <span id='Ext-form-Basic-method-beforeAction'>    /**
648 </span>     * @private
649      * Called before an action is performed via {@link #doAction}.
650      * @param {Ext.form.action.Action} action The Action instance that was invoked
651      */
652     beforeAction: function(action) {
653         var waitMsg = action.waitMsg,
654             maskCls = Ext.baseCSSPrefix + 'mask-loading',
655             waitMsgTarget;
656
657         // Call HtmlEditor's syncValue before actions
658         this.getFields().each(function(f) {
659             if (f.isFormField &amp;&amp; f.syncValue) {
660                 f.syncValue();
661             }
662         });
663
664         if (waitMsg) {
665             waitMsgTarget = this.waitMsgTarget;
666             if (waitMsgTarget === true) {
667                 this.owner.el.mask(waitMsg, maskCls);
668             } else if (waitMsgTarget) {
669                 waitMsgTarget = this.waitMsgTarget = Ext.get(waitMsgTarget);
670                 waitMsgTarget.mask(waitMsg, maskCls);
671             } else {
672                 Ext.MessageBox.wait(waitMsg, action.waitTitle || this.waitTitle);
673             }
674         }
675     },
676
677 <span id='Ext-form-Basic-method-afterAction'>    /**
678 </span>     * @private
679      * Called after an action is performed via {@link #doAction}.
680      * @param {Ext.form.action.Action} action The Action instance that was invoked
681      * @param {Boolean} success True if the action completed successfully, false, otherwise.
682      */
683     afterAction: function(action, success) {
684         if (action.waitMsg) {
685             var MessageBox = Ext.MessageBox,
686                 waitMsgTarget = this.waitMsgTarget;
687             if (waitMsgTarget === true) {
688                 this.owner.el.unmask();
689             } else if (waitMsgTarget) {
690                 waitMsgTarget.unmask();
691             } else {
692                 MessageBox.updateProgress(1);
693                 MessageBox.hide();
694             }
695         }
696         if (success) {
697             if (action.reset) {
698                 this.reset();
699             }
700             Ext.callback(action.success, action.scope || action, [this, action]);
701             this.fireEvent('actioncomplete', this, action);
702         } else {
703             Ext.callback(action.failure, action.scope || action, [this, action]);
704             this.fireEvent('actionfailed', this, action);
705         }
706     },
707
708
709 <span id='Ext-form-Basic-method-findField'>    /**
710 </span>     * Find a specific {@link Ext.form.field.Field} in this form by id or name.
711      * @param {String} id The value to search for (specify either a {@link Ext.Component#id id} or
712      * {@link Ext.form.field.Field#getName name or hiddenName}).
713      * @return Ext.form.field.Field The first matching field, or &lt;tt&gt;null&lt;/tt&gt; if none was found.
714      */
715     findField: function(id) {
716         return this.getFields().findBy(function(f) {
717             return f.id === id || f.getName() === id;
718         });
719     },
720
721
722 <span id='Ext-form-Basic-method-markInvalid'>    /**
723 </span>     * Mark fields in this form invalid in bulk.
724      * @param {Array/Object} errors Either an array in the form &lt;code&gt;[{id:'fieldId', msg:'The message'}, ...]&lt;/code&gt;,
725      * an object hash of &lt;code&gt;{id: msg, id2: msg2}&lt;/code&gt;, or a {@link Ext.data.Errors} object.
726      * @return {Ext.form.Basic} this
727      */
728     markInvalid: function(errors) {
729         var me = this;
730
731         function mark(fieldId, msg) {
732             var field = me.findField(fieldId);
733             if (field) {
734                 field.markInvalid(msg);
735             }
736         }
737
738         if (Ext.isArray(errors)) {
739             Ext.each(errors, function(err) {
740                 mark(err.id, err.msg);
741             });
742         }
743         else if (errors instanceof Ext.data.Errors) {
744             errors.each(function(err) {
745                 mark(err.field, err.message);
746             });
747         }
748         else {
749             Ext.iterate(errors, mark);
750         }
751         return this;
752     },
753
754 <span id='Ext-form-Basic-method-setValues'>    /**
755 </span>     * Set values for fields in this form in bulk.
756      * @param {Array/Object} values Either an array in the form:&lt;pre&gt;&lt;code&gt;
757 [{id:'clientName', value:'Fred. Olsen Lines'},
758  {id:'portOfLoading', value:'FXT'},
759  {id:'portOfDischarge', value:'OSL'} ]&lt;/code&gt;&lt;/pre&gt;
760      * or an object hash of the form:&lt;pre&gt;&lt;code&gt;
761 {
762     clientName: 'Fred. Olsen Lines',
763     portOfLoading: 'FXT',
764     portOfDischarge: 'OSL'
765 }&lt;/code&gt;&lt;/pre&gt;
766      * @return {Ext.form.Basic} this
767      */
768     setValues: function(values) {
769         var me = this;
770
771         function setVal(fieldId, val) {
772             var field = me.findField(fieldId);
773             if (field) {
774                 field.setValue(val);
775                 if (me.trackResetOnLoad) {
776                     field.resetOriginalValue();
777                 }
778             }
779         }
780
781         if (Ext.isArray(values)) {
782             // array of objects
783             Ext.each(values, function(val) {
784                 setVal(val.id, val.value);
785             });
786         } else {
787             // object hash
788             Ext.iterate(values, setVal);
789         }
790         return this;
791     },
792
793 <span id='Ext-form-Basic-method-getValues'>    /**
794 </span>     * Retrieves the fields in the form as a set of key/value pairs, using their
795      * {@link Ext.form.field.Field#getSubmitData getSubmitData()} method to collect the values.
796      * If multiple fields return values under the same name those values will be combined into an Array.
797      * This is similar to {@link #getFieldValues} except that this method collects only String values for
798      * submission, while getFieldValues collects type-specific data values (e.g. Date objects for date fields.)
799      * @param {Boolean} asString (optional) If true, will return the key/value collection as a single
800      * URL-encoded param string. Defaults to false.
801      * @param {Boolean} dirtyOnly (optional) If true, only fields that are dirty will be included in the result.
802      * Defaults to false.
803      * @param {Boolean} includeEmptyText (optional) If true, the configured emptyText of empty fields will be used.
804      * Defaults to false.
805      * @return {String/Object}
806      */
807     getValues: function(asString, dirtyOnly, includeEmptyText, useDataValues) {
808         var values = {};
809
810         this.getFields().each(function(field) {
811             if (!dirtyOnly || field.isDirty()) {
812                 var data = field[useDataValues ? 'getModelData' : 'getSubmitData'](includeEmptyText);
813                 if (Ext.isObject(data)) {
814                     Ext.iterate(data, function(name, val) {
815                         if (includeEmptyText &amp;&amp; val === '') {
816                             val = field.emptyText || '';
817                         }
818                         if (name in values) {
819                             var bucket = values[name],
820                                 isArray = Ext.isArray;
821                             if (!isArray(bucket)) {
822                                 bucket = values[name] = [bucket];
823                             }
824                             if (isArray(val)) {
825                                 values[name] = bucket.concat(val);
826                             } else {
827                                 bucket.push(val);
828                             }
829                         } else {
830                             values[name] = val;
831                         }
832                     });
833                 }
834             }
835         });
836
837         if (asString) {
838             values = Ext.Object.toQueryString(values);
839         }
840         return values;
841     },
842
843 <span id='Ext-form-Basic-method-getFieldValues'>    /**
844 </span>     * Retrieves the fields in the form as a set of key/value pairs, using their
845      * {@link Ext.form.field.Field#getModelData getModelData()} method to collect the values.
846      * If multiple fields return values under the same name those values will be combined into an Array.
847      * This is similar to {@link #getValues} except that this method collects type-specific data values
848      * (e.g. Date objects for date fields) while getValues returns only String values for submission.
849      * @param {Boolean} dirtyOnly (optional) If true, only fields that are dirty will be included in the result.
850      * Defaults to false.
851      * @return {Object}
852      */
853     getFieldValues: function(dirtyOnly) {
854         return this.getValues(false, dirtyOnly, false, true);
855     },
856
857 <span id='Ext-form-Basic-method-clearInvalid'>    /**
858 </span>     * Clears all invalid field messages in this form.
859      * @return {Ext.form.Basic} this
860      */
861     clearInvalid: function() {
862         var me = this;
863         me.batchLayouts(function() {
864             me.getFields().each(function(f) {
865                 f.clearInvalid();
866             });
867         });
868         return me;
869     },
870
871 <span id='Ext-form-Basic-method-reset'>    /**
872 </span>     * Resets all fields in this form.
873      * @return {Ext.form.Basic} this
874      */
875     reset: function() {
876         var me = this;
877         me.batchLayouts(function() {
878             me.getFields().each(function(f) {
879                 f.reset();
880             });
881         });
882         return me;
883     },
884
885 <span id='Ext-form-Basic-method-applyToFields'>    /**
886 </span>     * Calls {@link Ext#apply Ext.apply} for all fields in this form with the passed object.
887      * @param {Object} obj The object to be applied
888      * @return {Ext.form.Basic} this
889      */
890     applyToFields: function(obj) {
891         this.getFields().each(function(f) {
892             Ext.apply(f, obj);
893         });
894         return this;
895     },
896
897 <span id='Ext-form-Basic-method-applyIfToFields'>    /**
898 </span>     * Calls {@link Ext#applyIf Ext.applyIf} for all field in this form with the passed object.
899      * @param {Object} obj The object to be applied
900      * @return {Ext.form.Basic} this
901      */
902     applyIfToFields: function(obj) {
903         this.getFields().each(function(f) {
904             Ext.applyIf(f, obj);
905         });
906         return this;
907     },
908
909 <span id='Ext-form-Basic-method-batchLayouts'>    /**
910 </span>     * @private
911      * Utility wrapper that suspends layouts of all field parent containers for the duration of a given
912      * function. Used during full-form validation and resets to prevent huge numbers of layouts.
913      * @param {Function} fn
914      */
915     batchLayouts: function(fn) {
916         var me = this,
917             suspended = new Ext.util.HashMap();
918
919         // Temporarily suspend layout on each field's immediate owner so we don't get a huge layout cascade
920         me.getFields().each(function(field) {
921             var ownerCt = field.ownerCt;
922             if (!suspended.contains(ownerCt)) {
923                 suspended.add(ownerCt);
924                 ownerCt.oldSuspendLayout = ownerCt.suspendLayout;
925                 ownerCt.suspendLayout = true;
926             }
927         });
928
929         // Invoke the function
930         fn();
931
932         // Un-suspend the container layouts
933         suspended.each(function(id, ct) {
934             ct.suspendLayout = ct.oldSuspendLayout;
935             delete ct.oldSuspendLayout;
936         });
937
938         // Trigger a single layout
939         me.owner.doComponentLayout();
940     }
941 });
942 </pre>
943 </body>
944 </html>