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 {Roo.form.LayoutDialog} dialog
87 * If you set this to a Roo.form.Dialog, it will get masked when saving..
90 * @cfg {Object} baseParams
91 * Parameters to pass with all requests. e.g. baseParams: {id: '123', foo: 'bar'}.
96 * @cfg {Number} timeout Timeout for form actions in seconds (default is 30 seconds).
104 * @cfg {Boolean} trackResetOnLoad If set to true, form.reset() resets to the last loaded
105 * or setValues() data instead of when the form was first created.
107 trackResetOnLoad : false,
111 * childForms - used for multi-tab forms
117 * allItems - full list of fields.
123 * By default wait messages are displayed with Roo.MessageBox.wait. You can target a specific
124 * element by passing it or its id or mask the form itself by passing in true.
127 waitMsgTarget : undefined,
130 initEl : function(el){
131 this.el = Roo.get(el);
132 this.id = this.el.id || Roo.id();
133 this.el.on('submit', this.onSubmit, this);
134 this.el.addClass('x-form');
138 onSubmit : function(e){
143 * Returns true if client-side validation on the form is successful.
146 isValid : function(){
148 this.items.each(function(f){
157 * Returns true if any fields in this form have changed since their original load.
160 isDirty : function(){
162 this.items.each(function(f){
172 * Performs a predefined action (submit or load) or custom actions you define on this form.
173 * @param {String} actionName The name of the action type
174 * @param {Object} options (optional) The options to pass to the action. All of the config options listed
175 * below are supported by both the submit and load actions unless otherwise noted (custom actions could also
176 * accept other config options):
178 Property Type Description
179 ---------------- --------------- ----------------------------------------------------------------------------------
180 url String The url for the action (defaults to the form's url)
181 method String The form method to use (defaults to the form's method, or POST if not defined)
182 params String/Object The params to pass (defaults to the form's baseParams, or none if not defined)
183 clientValidation Boolean Applies to submit only. Pass true to call form.isValid() prior to posting to
184 validate the form on the client (defaults to false)
186 * @return {BasicForm} this
188 doAction : function(action, options){
189 if(typeof action == 'string'){
190 action = new Roo.form.Action.ACTION_TYPES[action](this, options);
192 if(this.fireEvent('beforeaction', this, action) !== false){
193 this.beforeAction(action);
194 action.run.defer(100, action);
200 * Shortcut to do a submit action.
201 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
202 * @return {BasicForm} this
204 submit : function(options){
205 this.doAction('submit', options);
210 * Shortcut to do a load action.
211 * @param {Object} options The options to pass to the action (see {@link #doAction} for details)
212 * @return {BasicForm} this
214 load : function(options){
215 this.doAction('load', options);
220 * Persists the values in this form into the passed Roo.data.Record object in a beginEdit/endEdit block.
221 * @param {Record} record The record to edit
222 * @return {BasicForm} this
224 updateRecord : function(record){
226 var fs = record.fields;
228 var field = this.findField(f.name);
230 record.set(f.name, field.getValue());
238 * Loads an Roo.data.Record into this form.
239 * @param {Record} record The record to load
240 * @return {BasicForm} this
242 loadRecord : function(record){
243 this.setValues(record.data);
248 beforeAction : function(action){
249 var o = action.options;
252 o.waitMsg = o.waitMsg || true;
253 o.waitMsgTarget = this.dialog.el;
256 if(this.waitMsgTarget === true){
257 this.el.mask(o.waitMsg, 'x-mask-loading');
258 }else if(this.waitMsgTarget){
259 this.waitMsgTarget = Roo.get(this.waitMsgTarget);
260 this.waitMsgTarget.mask(o.waitMsg, 'x-mask-loading');
262 Roo.MessageBox.wait(o.waitMsg, o.waitTitle || this.waitTitle || 'Please Wait...');
268 afterAction : function(action, success){
269 this.activeAction = null;
270 var o = action.options;
272 if(this.waitMsgTarget === true){
274 }else if(this.waitMsgTarget){
275 this.waitMsgTarget.unmask();
277 Roo.MessageBox.updateProgress(1);
278 Roo.MessageBox.hide();
285 Roo.callback(o.success, o.scope, [this, action]);
286 this.fireEvent('actioncomplete', this, action);
289 Roo.callback(o.failure, o.scope, [this, action]);
290 // show an error message if no failed handler is set..
291 if (!this.hasListener('actionfailed')) {
292 Roo.MessageBox.alert("Error", "Saving Failed, please check your entries");
295 this.fireEvent('actionfailed', this, action);
301 * Find a Roo.form.Field in this form by id, dataIndex, name or hiddenName
302 * @param {String} id The value to search for
305 findField : function(id){
306 var field = this.items.get(id);
308 this.items.each(function(f){
309 if(f.isFormField && (f.dataIndex == id || f.id == id || f.getName() == id)){
315 return field || null;
319 * Add a secondary form to this one,
320 * Used to provide tabbed forms. One form is primary, with hidden values
321 * which mirror the elements from the other forms.
323 * @param {Roo.form.Form} form to add.
326 addForm : function(form)
329 if (this.childForms.indexOf(form) > -1) {
333 this.childForms.push(form);
335 Roo.each(form.allItems, function (fe) {
337 n = typeof(fe.getName) == 'undefined' ? fe.name : fe.getName();
338 if (this.findField(n)) { // already added..
341 var add = new Roo.form.Hidden({
351 * Mark fields in this form invalid in bulk.
352 * @param {Array/Object} errors Either an array in the form [{id:'fieldId', msg:'The message'},...] or an object hash of {id: msg, id2: msg2}
353 * @return {BasicForm} this
355 markInvalid : function(errors){
356 if(errors instanceof Array){
357 for(var i = 0, len = errors.length; i < len; i++){
358 var fieldError = errors[i];
359 var f = this.findField(fieldError.id);
361 f.markInvalid(fieldError.msg);
367 if(typeof errors[id] != 'function' && (field = this.findField(id))){
368 field.markInvalid(errors[id]);
372 Roo.each(this.childForms || [], function (f) {
373 f.markInvalid(errors);
380 * Set values for fields in this form in bulk.
381 * @param {Array/Object} values Either an array in the form [{id:'fieldId', value:'foo'},...] or an object hash of {id: value, id2: value2}
382 * @return {BasicForm} this
384 setValues : function(values){
385 if(values instanceof Array){ // array of objects
386 for(var i = 0, len = values.length; i < len; i++){
388 var f = this.findField(v.id);
391 if(this.trackResetOnLoad){
392 f.originalValue = f.getValue();
396 }else{ // object hash
399 if(typeof values[id] != 'function' && (field = this.findField(id))){
401 if (field.setFromData &&
403 field.displayField &&
404 // combos' with local stores can
405 // be queried via setValue()
406 // to set their value..
407 (field.store && !field.store.isLocal)
411 sd[field.valueField] = typeof(values[field.hiddenName]) == 'undefined' ? '' : values[field.hiddenName];
412 sd[field.displayField] = typeof(values[field.name]) == 'undefined' ? '' : values[field.name];
413 field.setFromData(sd);
416 field.setValue(values[id]);
420 if(this.trackResetOnLoad){
421 field.originalValue = field.getValue();
427 Roo.each(this.childForms || [], function (f) {
435 * Returns the fields in this form as an object with key/value pairs. If multiple fields exist with the same name
436 * they are returned as an array.
437 * @param {Boolean} asString
440 getValues : function(asString){
441 if (this.childForms) {
442 // copy values from the child forms
443 Roo.each(this.childForms, function (f) {
444 this.setValues(f.getValues());
450 var fs = Roo.lib.Ajax.serializeForm(this.el.dom);
451 if(asString === true){
454 return Roo.urlDecode(fs);
458 * Returns the fields in this form as an object with key/value pairs.
459 * This differs from getValues as it calls getValue on each child item, rather than using dom data.
462 getFieldValues : function()
464 if (this.childForms) {
465 // copy values from the child forms
466 Roo.each(this.childForms, function (f) {
467 this.setValues(f.getValues());
472 this.items.each(function(f){
476 var v = f.getValue();
477 if ((typeof(v) == 'object') && f.getRawValue) {
478 v = f.getRawValue() ; // dates..
480 ret[f.getName()] = v;
487 * Clears all invalid messages in this form.
488 * @return {BasicForm} this
490 clearInvalid : function(){
491 this.items.each(function(f){
495 Roo.each(this.childForms || [], function (f) {
505 * @return {BasicForm} this
508 this.items.each(function(f){
512 Roo.each(this.childForms || [], function (f) {
521 * Add Roo.form components to this form.
522 * @param {Field} field1
523 * @param {Field} field2 (optional)
524 * @param {Field} etc (optional)
525 * @return {BasicForm} this
528 this.items.addAll(Array.prototype.slice.call(arguments, 0));
534 * Removes a field from the items collection (does NOT remove its markup).
535 * @param {Field} field
536 * @return {BasicForm} this
538 remove : function(field){
539 this.items.remove(field);
544 * Looks at the fields in this form, checks them for an id attribute,
545 * and calls applyTo on the existing dom element with that id.
546 * @return {BasicForm} this
549 this.items.each(function(f){
550 if(f.isFormField && !f.rendered && document.getElementById(f.id)){ // if the element exists
558 * Calls {@link Ext#apply} for all fields in this form with the passed object.
559 * @param {Object} values
560 * @return {BasicForm} this
562 applyToFields : function(o){
563 this.items.each(function(f){
570 * Calls {@link Ext#applyIf} for all field in this form with the passed object.
571 * @param {Object} values
572 * @return {BasicForm} this
574 applyIfToFields : function(o){
575 this.items.each(function(f){
583 Roo.BasicForm = Roo.form.BasicForm;