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){
23 Roo.apply(this, config);
25 * The Roo.form.Field items in this form.
26 * @type MixedCollection
30 this.items = new Roo.util.MixedCollection(false, function(o){
31 return o.id || (o.id = Roo.id());
36 * Fires before any action is performed. Return false to cancel the action.
38 * @param {Action} action The action to be performed
43 * Fires when an action fails.
45 * @param {Action} action The action that failed
49 * @event actioncomplete
50 * Fires when an action is completed.
52 * @param {Action} action The action that completed
59 Roo.form.BasicForm.superclass.constructor.call(this);
62 Roo.extend(Roo.form.BasicForm, Roo.util.Observable, {
64 * @cfg {String} method
65 * The request method to use (GET or POST) for form actions if one isn't supplied in the action options.
68 * @cfg {DataReader} reader
69 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when executing "load" actions.
70 * This is optional as there is built-in support for processing JSON.
73 * @cfg {DataReader} errorReader
74 * An Roo.data.DataReader (e.g. {@link Roo.data.XmlReader}) to be used to read data when reading validation errors on "submit" actions.
75 * This is completely optional as there is built-in support for processing JSON.
79 * The URL to use for form actions if one isn't supplied in the action options.
82 * @cfg {Boolean} fileUpload
83 * Set to true if this form is a file upload.
86 * @cfg {Object} baseParams
87 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
90 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
98 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
99 * or setValues() data instead of when the form was first created.
101 trackResetOnLoad : false,
105 * childForms - used for multi-tab forms
111 * allItems - full list of fields.
117 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
118 * element by passing it or its id or mask the form itself by passing in true.
121 waitMsgTarget : undefined,
124 initEl : function(el){
125 this.el = Roo.get(el);
126 this.id = this.el.id || Roo.id();
127 this.el.on('submit', this.onSubmit, this);
128 this.el.addClass('x-form');
132 onSubmit : function(e){
137 * Returns true if client-side validation on the form is successful.
140 isValid : function(){
142 this.items.each(function(f){
151 * Returns true if any fields in this form have changed since their original load.
154 isDirty : function(){
156 this.items.each(function(f){
166 * Performs a predefined action (submit or load) or custom actions you define on this form.
167 * @param {String} actionName The name of the action type
168 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
169 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
170 * accept other config options):
172 Property Type Description
173 ---------------- --------------- ----------------------------------------------------------------------------------
174 url String The url for the action (defaults to the form's url)
175 method String The form method to use (defaults to the form's method, or POST if not defined)
176 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
177 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
178 validate the form on the client (defaults to false)
180 * @return {BasicForm} this
182 doAction : function(action, options){
183 if(typeof action == 'string'){
184 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
186 if(this.fireEvent('beforeaction', this, action) !== false){
187 this.beforeAction(action);
188 action.run.defer(100, action);
194 * Shortcut to do a submit action.
195 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
196 * @return {BasicForm} this
198 submit : function(options){
199 this.doAction('submit', options);
204 * Shortcut to do a load action.
205 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
206 * @return {BasicForm} this
208 load : function(options){
209 this.doAction('load', options);
214 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
215 * @param {Record} record The record to edit
216 * @return {BasicForm} this
218 updateRecord : function(record){
220 var fs = record.fields;
222 var field = this.findField(f.name);
224 record.set(f.name, field.getValue());
232 * Loads an Roo.data.Record into this form.
233 * @param {Record} record The record to load
234 * @return {BasicForm} this
236 loadRecord : function(record){
237 this.setValues(record.data);
242 beforeAction : function(action){
243 var o = action.options;
245 if(this.waitMsgTarget === true){
246 this.el.mask(o.waitMsg, 'x-mask-loading');
247 }else if(this.waitMsgTarget){
248 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
249 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
251 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
257 afterAction : function(action, success){
258 this.activeAction = null;
259 var o = action.options;
261 if(this.waitMsgTarget === true){
263 }else if(this.waitMsgTarget){
264 this.waitMsgTarget.unmask();
266 Roo.MessageBox.updateProgress(1);
267 Roo.MessageBox.hide();
274 Roo.callback(o.success, o.scope, [this, action]);
275 this.fireEvent('actioncomplete', this, action);
277 Roo.callback(o.failure, o.scope, [this, action]);
278 this.fireEvent('actionfailed', this, action);
283 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
284 * @param {String} id The value to search for
287 findField : function(id){
288 var field = this.items.get(id);
290 this.items.each(function(f){
291 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
297 return field || null;
301 * Add a secondary form to this one,
302 * Used to provide tabbed forms. One form is primary, with hidden values
303 * which mirror the elements from the other forms.
305 * @param {Roo.form.Form} form to add.
308 addForm : function(form){
310 this.childForms.push(form);
311 Roo.each(form.allItems, function (fe) {
313 if (this.findField(fe.name)) { // already added..
316 var add = new Roo.form.Hidden({
320 this.add( new Roo.form.Hidden({
327 * Mark fields in this form invalid in bulk.
328 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
329 * @return {BasicForm} this
331 markInvalid : function(errors){
332 if(errors instanceof Array){
333 for(var i = 0, len = errors.length; i < len; i++){
334 var fieldError = errors[i];
335 var f = this.findField(fieldError.id);
337 f.markInvalid(fieldError.msg);
343 if(typeof errors[id] != 'function' && (field = this.findField(id))){
344 field.markInvalid(errors[id]);
348 Roo.each(this.childForms || [], function (f) {
349 f.markInvalid(errors);
356 * Set values for fields in this form in bulk.
357 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
358 * @return {BasicForm} this
360 setValues : function(values){
361 if(values instanceof Array){ // array of objects
362 for(var i = 0, len = values.length; i < len; i++){
364 var f = this.findField(v.id);
367 if(this.trackResetOnLoad){
368 f.originalValue = f.getValue();
372 }else{ // object hash
375 if(typeof values[id] != 'function' && (field = this.findField(id))){
377 if (field.setFromData &&
379 field.displayField &&
380 // combos' with local stores can
381 // be queried via setValue()
382 // to set their value..
383 (field.store && !field.store.isLocal)
387 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
388 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
389 field.setFromData(sd);
392 field.setValue(values[id]);
396 if(this.trackResetOnLoad){
397 field.originalValue = field.getValue();
403 Roo.each(this.childForms || [], function (f) {
411 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
412 * they are returned as an array.
413 * @param {Boolean} asString
416 getValues : function(asString){
417 if (this.childForms) {
418 // copy values from the child forms
419 Roo.each(this.childForms, function (f) {
421 Roo.each(f.allFields, function (e) {
422 if (e.name && e.getValue && this.findField(e.name)) {
423 this.findField(e.name).setValue(e.getValue());
432 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
433 if(asString === true){
436 return Roo.urlDecode(fs);
440 * Clears all invalid messages in this form.
441 * @return {BasicForm} this
443 clearInvalid : function(){
444 this.items.each(function(f){
448 Roo.each(this.childForms || [], function (f) {
458 * @return {BasicForm} this
461 this.items.each(function(f){
465 Roo.each(this.childForms || [], function (f) {
474 * Add Roo.form components to this form.
475 * @param {Field} field1
476 * @param {Field} field2 (optional)
477 * @param {Field} etc (optional)
478 * @return {BasicForm} this
481 this.items.addAll(Array.prototype.slice.call(arguments, 0));
487 * Removes a field from the items collection (does NOT remove its markup).
488 * @param {Field} field
489 * @return {BasicForm} this
491 remove : function(field){
492 this.items.remove(field);
497 * Looks at the fields in this form, checks them for an id attribute,
498 * and calls applyTo on the existing dom element with that id.
499 * @return {BasicForm} this
502 this.items.each(function(f){
503 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
511 * Calls {@link Ext#apply} for all fields in this form with the passed object.
512 * @param {Object} values
513 * @return {BasicForm} this
515 applyToFields : function(o){
516 this.items.each(function(f){
523 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
524 * @param {Object} values
525 * @return {BasicForm} this
527 applyIfToFields : function(o){
528 this.items.each(function(f){
536 Roo.BasicForm = Roo.form.BasicForm;