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){
21 Roo.apply(this, config);
23 * The Roo.form.Field items in this form.
24 * @type MixedCollection
26 this.items = new Roo.util.MixedCollection(false, function(o){
27 return o.id || (o.id = Roo.id());
32 * Fires before any action is performed. Return false to cancel the action.
34 * @param {Action} action The action to be performed
39 * Fires when an action fails.
41 * @param {Action} action The action that failed
45 * @event actioncomplete
46 * Fires when an action is completed.
48 * @param {Action} action The action that completed
55 Roo.form.BasicForm.superclass.constructor.call(this);
58 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
60 * @cfg {String} method
61 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
64 * @cfg {DataReader} reader
65 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
66 * This is optional as there is built-in support for processing JSON.
69 * @cfg {DataReader} errorReader
70 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
71 * This is completely optional as there is built-in support for processing JSON.
75 * The URL to use for form actions if one isn't supplied in the action options.
78 * @cfg {Boolean} fileUpload
79 * Set to true if this form is a file upload.
82 * @cfg {Object} baseParams
83 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
86 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
94 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
95 * or setValues() data instead of when the form was first created.
97 trackResetOnLoad : false,
101 * childForms - used for multi-tab forms
107 * allFields - full list of fields.
113 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
114 * element by passing it or its id or mask the form itself by passing in true.
117 waitMsgTarget : undefined,
120 initEl : function(el){
121 this.el = Roo.get(el);
122 this.id = this.el.id || Roo.id();
123 this.el.on('submit', this.onSubmit, this);
124 this.el.addClass('x-form');
128 onSubmit : function(e){
133 * Returns true if client-side validation on the form is successful.
136 isValid : function(){
138 this.items.each(function(f){
147 * Returns true if any fields in this form have changed since their original load.
150 isDirty : function(){
152 this.items.each(function(f){
162 * Performs a predefined action (submit or load) or custom actions you define on this form.
163 * @param {String} actionName The name of the action type
164 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
165 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
166 * accept other config options):
168 Property Type Description
169 ---------------- --------------- ----------------------------------------------------------------------------------
170 url String The url for the action (defaults to the form's url)
171 method String The form method to use (defaults to the form's method, or POST if not defined)
172 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
173 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
174 validate the form on the client (defaults to false)
176 * @return {BasicForm} this
178 doAction : function(action, options){
179 if(typeof action == 'string'){
180 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
182 if(this.fireEvent('beforeaction', this, action) !== false){
183 this.beforeAction(action);
184 action.run.defer(100, action);
190 * Shortcut to do a submit action.
191 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
192 * @return {BasicForm} this
194 submit : function(options){
195 this.doAction('submit', options);
200 * Shortcut to do a load action.
201 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
202 * @return {BasicForm} this
204 load : function(options){
205 this.doAction('load', options);
210 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
211 * @param {Record} record The record to edit
212 * @return {BasicForm} this
214 updateRecord : function(record){
216 var fs = record.fields;
218 var field = this.findField(f.name);
220 record.set(f.name, field.getValue());
228 * Loads an Roo.data.Record into this form.
229 * @param {Record} record The record to load
230 * @return {BasicForm} this
232 loadRecord : function(record){
233 this.setValues(record.data);
238 beforeAction : function(action){
239 var o = action.options;
241 if(this.waitMsgTarget === true){
242 this.el.mask(o.waitMsg, 'x-mask-loading');
243 }else if(this.waitMsgTarget){
244 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
245 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
247 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
253 afterAction : function(action, success){
254 this.activeAction = null;
255 var o = action.options;
257 if(this.waitMsgTarget === true){
259 }else if(this.waitMsgTarget){
260 this.waitMsgTarget.unmask();
262 Roo.MessageBox.updateProgress(1);
263 Roo.MessageBox.hide();
270 Roo.callback(o.success, o.scope, [this, action]);
271 this.fireEvent('actioncomplete', this, action);
273 Roo.callback(o.failure, o.scope, [this, action]);
274 this.fireEvent('actionfailed', this, action);
279 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
280 * @param {String} id The value to search for
283 findField : function(id){
284 var field = this.items.get(id);
286 this.items.each(function(f){
287 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
293 return field || null;
297 * Add a secondary form to this one,
298 * Used to provide tabbed forms. One form is primary, with hidden values
299 * which mirror the elements from the other forms.
301 * @param {Roo.form.Form} form to add.
304 addForm : function(form){
306 this.childForms.push(form);
307 form.allItems.each(function (fe) {
309 if (this.findField(fe.name)) { // already added..
312 this.add( new Roo.form.Hidden({
319 * Mark fields in this form invalid in bulk.
320 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
321 * @return {BasicForm} this
323 markInvalid : function(errors){
324 if(errors instanceof Array){
325 for(var i = 0, len = errors.length; i < len; i++){
326 var fieldError = errors[i];
327 var f = this.findField(fieldError.id);
329 f.markInvalid(fieldError.msg);
335 if(typeof errors[id] != 'function' && (field = this.findField(id))){
336 field.markInvalid(errors[id]);
340 Roo.each(this.childForms || [], function (f) {
341 f.markInvalid(errors);
348 * Set values for fields in this form in bulk.
349 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
350 * @return {BasicForm} this
352 setValues : function(values){
353 if(values instanceof Array){ // array of objects
354 for(var i = 0, len = values.length; i < len; i++){
356 var f = this.findField(v.id);
359 if(this.trackResetOnLoad){
360 f.originalValue = f.getValue();
364 }else{ // object hash
367 if(typeof values[id] != 'function' && (field = this.findField(id))){
369 if (field.setFromData &&
371 field.displayField &&
372 // combos' with local stores can
373 // be queried via setValue()
374 // to set their value..
375 (field.store && !field.store.isLocal)
379 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
380 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
381 field.setFromData(sd);
384 field.setValue(values[id]);
388 if(this.trackResetOnLoad){
389 field.originalValue = field.getValue();
395 Roo.each(this.childForms || [], function (f) {
403 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
404 * they are returned as an array.
405 * @param {Boolean} asString
408 getValues : function(asString){
409 if (this.childForms) {
410 // copy values from the child forms
411 Roo.each(this.childForms, function (f) {
413 Roo.each(f.allFields, function (e) {
414 if (e.name && e.getValue && this.findField(e.name)) {
415 this.findField(e.name).setValue(e.getValue());
424 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
425 if(asString === true){
428 return Roo.urlDecode(fs);
432 * Clears all invalid messages in this form.
433 * @return {BasicForm} this
435 clearInvalid : function(){
436 this.items.each(function(f){
440 Roo.each(this.childForms || [], function (f) {
450 * @return {BasicForm} this
453 this.items.each(function(f){
457 Roo.each(this.childForms || [], function (f) {
466 * Add Roo.form components to this form.
467 * @param {Field} field1
468 * @param {Field} field2 (optional)
469 * @param {Field} etc (optional)
470 * @return {BasicForm} this
473 this.items.addAll(Array.prototype.slice.call(arguments, 0));
479 * Removes a field from the items collection (does NOT remove its markup).
480 * @param {Field} field
481 * @return {BasicForm} this
483 remove : function(field){
484 this.items.remove(field);
489 * Looks at the fields in this form, checks them for an id attribute,
490 * and calls applyTo on the existing dom element with that id.
491 * @return {BasicForm} this
494 this.items.each(function(f){
495 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
503 * Calls {@link Ext#apply} for all fields in this form with the passed object.
504 * @param {Object} values
505 * @return {BasicForm} this
507 applyToFields : function(o){
508 this.items.each(function(f){
515 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
516 * @param {Object} values
517 * @return {BasicForm} this
519 applyIfToFields : function(o){
520 this.items.each(function(f){
528 Roo.BasicForm = Roo.form.BasicForm;