4 * Copyright(c) 2006-2007, Ext JS, LLC.
6 * Originally Released Under LGPL - original licence link has changed is not relivant.
9 * <script type="text/javascript">
13 * @class Roo.form.BasicForm
14 * @extends Roo.util.Observable
15 * Supplies the functionality to do "actions" on forms and initialize Roo.form.Field types on existing markup.
17 * @param {String/HTMLElement/Roo.Element} el The form element or its id
18 * @param {Object} config Configuration options
20 Roo.form.BasicForm = function(el, config){
22 Roo.apply(this, config);
24 * The Roo.form.Field items in this form.
25 * @type MixedCollection
29 this.items = new Roo.util.MixedCollection(false, function(o){
30 return o.id || (o.id = Roo.id());
35 * Fires before any action is performed. Return false to cancel the action.
37 * @param {Action} action The action to be performed
42 * Fires when an action fails.
44 * @param {Action} action The action that failed
48 * @event actioncomplete
49 * Fires when an action is completed.
51 * @param {Action} action The action that completed
58 Roo.form.BasicForm.superclass.constructor.call(this);
61 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
63 * @cfg {String} method
64 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
67 * @cfg {DataReader} reader
68 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
69 * This is optional as there is built-in support for processing JSON.
72 * @cfg {DataReader} errorReader
73 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
74 * This is completely optional as there is built-in support for processing JSON.
78 * The URL to use for form actions if one isn't supplied in the action options.
81 * @cfg {Boolean} fileUpload
82 * Set to true if this form is a file upload.
85 * @cfg {Object} baseParams
86 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
89 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
97 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
98 * or setValues() data instead of when the form was first created.
100 trackResetOnLoad : false,
104 * childForms - used for multi-tab forms
110 * allFields - full list of fields.
116 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
117 * element by passing it or its id or mask the form itself by passing in true.
120 waitMsgTarget : undefined,
123 initEl : function(el){
124 this.el = Roo.get(el);
125 this.id = this.el.id || Roo.id();
126 this.el.on('submit', this.onSubmit, this);
127 this.el.addClass('x-form');
131 onSubmit : function(e){
136 * Returns true if client-side validation on the form is successful.
139 isValid : function(){
141 this.items.each(function(f){
150 * Returns true if any fields in this form have changed since their original load.
153 isDirty : function(){
155 this.items.each(function(f){
165 * Performs a predefined action (submit or load) or custom actions you define on this form.
166 * @param {String} actionName The name of the action type
167 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
168 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
169 * accept other config options):
171 Property Type Description
172 ---------------- --------------- ----------------------------------------------------------------------------------
173 url String The url for the action (defaults to the form's url)
174 method String The form method to use (defaults to the form's method, or POST if not defined)
175 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
176 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
177 validate the form on the client (defaults to false)
179 * @return {BasicForm} this
181 doAction : function(action, options){
182 if(typeof action == 'string'){
183 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
185 if(this.fireEvent('beforeaction', this, action) !== false){
186 this.beforeAction(action);
187 action.run.defer(100, action);
193 * Shortcut to do a submit action.
194 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
195 * @return {BasicForm} this
197 submit : function(options){
198 this.doAction('submit', options);
203 * Shortcut to do a load action.
204 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
205 * @return {BasicForm} this
207 load : function(options){
208 this.doAction('load', options);
213 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
214 * @param {Record} record The record to edit
215 * @return {BasicForm} this
217 updateRecord : function(record){
219 var fs = record.fields;
221 var field = this.findField(f.name);
223 record.set(f.name, field.getValue());
231 * Loads an Roo.data.Record into this form.
232 * @param {Record} record The record to load
233 * @return {BasicForm} this
235 loadRecord : function(record){
236 this.setValues(record.data);
241 beforeAction : function(action){
242 var o = action.options;
244 if(this.waitMsgTarget === true){
245 this.el.mask(o.waitMsg, 'x-mask-loading');
246 }else if(this.waitMsgTarget){
247 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
248 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
250 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
256 afterAction : function(action, success){
257 this.activeAction = null;
258 var o = action.options;
260 if(this.waitMsgTarget === true){
262 }else if(this.waitMsgTarget){
263 this.waitMsgTarget.unmask();
265 Roo.MessageBox.updateProgress(1);
266 Roo.MessageBox.hide();
273 Roo.callback(o.success, o.scope, [this, action]);
274 this.fireEvent('actioncomplete', this, action);
276 Roo.callback(o.failure, o.scope, [this, action]);
277 this.fireEvent('actionfailed', this, action);
282 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
283 * @param {String} id The value to search for
286 findField : function(id){
287 var field = this.items.get(id);
289 this.items.each(function(f){
290 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
296 return field || null;
300 * Add a secondary form to this one,
301 * Used to provide tabbed forms. One form is primary, with hidden values
302 * which mirror the elements from the other forms.
304 * @param {Roo.form.Form} form to add.
307 addForm : function(form){
309 this.childForms.push(form);
310 form.allItems.each(function (fe) {
312 if (this.findField(fe.name)) { // already added..
315 this.add( new Roo.form.Hidden({
322 * Mark fields in this form invalid in bulk.
323 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
324 * @return {BasicForm} this
326 markInvalid : function(errors){
327 if(errors instanceof Array){
328 for(var i = 0, len = errors.length; i < len; i++){
329 var fieldError = errors[i];
330 var f = this.findField(fieldError.id);
332 f.markInvalid(fieldError.msg);
338 if(typeof errors[id] != 'function' && (field = this.findField(id))){
339 field.markInvalid(errors[id]);
343 Roo.each(this.childForms || [], function (f) {
344 f.markInvalid(errors);
351 * Set values for fields in this form in bulk.
352 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
353 * @return {BasicForm} this
355 setValues : function(values){
356 if(values instanceof Array){ // array of objects
357 for(var i = 0, len = values.length; i < len; i++){
359 var f = this.findField(v.id);
362 if(this.trackResetOnLoad){
363 f.originalValue = f.getValue();
367 }else{ // object hash
370 if(typeof values[id] != 'function' && (field = this.findField(id))){
372 if (field.setFromData &&
374 field.displayField &&
375 // combos' with local stores can
376 // be queried via setValue()
377 // to set their value..
378 (field.store && !field.store.isLocal)
382 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
383 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
384 field.setFromData(sd);
387 field.setValue(values[id]);
391 if(this.trackResetOnLoad){
392 field.originalValue = field.getValue();
398 Roo.each(this.childForms || [], function (f) {
406 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
407 * they are returned as an array.
408 * @param {Boolean} asString
411 getValues : function(asString){
412 if (this.childForms) {
413 // copy values from the child forms
414 Roo.each(this.childForms, function (f) {
416 Roo.each(f.allFields, function (e) {
417 if (e.name && e.getValue && this.findField(e.name)) {
418 this.findField(e.name).setValue(e.getValue());
427 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
428 if(asString === true){
431 return Roo.urlDecode(fs);
435 * Clears all invalid messages in this form.
436 * @return {BasicForm} this
438 clearInvalid : function(){
439 this.items.each(function(f){
443 Roo.each(this.childForms || [], function (f) {
453 * @return {BasicForm} this
456 this.items.each(function(f){
460 Roo.each(this.childForms || [], function (f) {
469 * Add Roo.form components to this form.
470 * @param {Field} field1
471 * @param {Field} field2 (optional)
472 * @param {Field} etc (optional)
473 * @return {BasicForm} this
476 this.items.addAll(Array.prototype.slice.call(arguments, 0));
482 * Removes a field from the items collection (does NOT remove its markup).
483 * @param {Field} field
484 * @return {BasicForm} this
486 remove : function(field){
487 this.items.remove(field);
492 * Looks at the fields in this form, checks them for an id attribute,
493 * and calls applyTo on the existing dom element with that id.
494 * @return {BasicForm} this
497 this.items.each(function(f){
498 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
506 * Calls {@link Ext#apply} for all fields in this form with the passed object.
507 * @param {Object} values
508 * @return {BasicForm} this
510 applyToFields : function(o){
511 this.items.each(function(f){
518 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
519 * @param {Object} values
520 * @return {BasicForm} this
522 applyIfToFields : function(o){
523 this.items.each(function(f){
531 Roo.BasicForm = Roo.form.BasicForm;