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