PDA

View Full Version : FormPanel: to display and edit a field using a different type to it's stored value



murrah
29 Dec 2008, 2:52 PM
Hi,

I have a formPanel with a field that displays an elapsed time in decimal hours eg 1.25. The user can also edit that value. Because of other features of the application, the data in the sqLite store field is actually stored in integer seconds rather than real hours.

Now, the problem was how to display the data in decimal hours, allow the user to edit it then save the result back to the db as seconds. After much searching of forums and tutorials and not really finding what I wanted I eventually came with this solution that others might find useful.

First, add a new config item for a field that needs this functionality. You can call it whatever you like and for this example I am using "mySavedValue".

var tfSchedHours = new Ext.form.NumberField({
fieldLabel: 'Scheduled hours',
name: 'schedSecs',
allowBlank:false,
blankText:'You must enter a number',
allowDecimals:true,
decimalPrecision:2,
minValue:0,
width: 50,
mySavedValue: 0 // Add this config option
});

The field is plugged into a formPanel as normal.

Next, when you load the data to the form (as shown below) you need to add the lines as indicated:


// Get the db record from the store. The getTask() is my function, not an Ext method.
var task = this.getTask();
// Get a handle to the form
var frm = this.getForm();
// Load the db record to the form
frm.loadRecord(task);
// Convert the value from seconds to decimal hours eg 4500 becomes 1.25
// and set that value on the field. Note that Ext.secs2DecimalHoursFormat is my function, not an ext method
frm.findField('schedSecs').setValue(Ext.secs2DecimalHoursFormat(task.data.schedSecs));

The only change to what you would normally do is to add the line converting the seconds to decimal hours.

Next, in your save form handler you do this (simplified for this example):

,saveData: function(){

var task = this.getTask(); // Load the original data from the sqlite store as normal

var frm = this.getForm(); // Get a reference to the form object

// Now take the value from the data entry box and convert that to seconds eg if user enters "2" convert that to 7200 and save that in the mySavedValue config item for that field

frm.findField('schedSecs').mySavedValue = Ext.decimalHours2SecsFormat(frm.findField('schedSecs').getValue());

// Update the database via the form store as normal
frm.updateRecord(task);

}

The only change to what you would normally do is to add the line converting the decimal hours to seconds.

Now, this is the override to the Ext updateRecord method that is called when you save the form (previous step):

Ext.override(Ext.form.BasicForm, {

updateRecord : function(record){
record.beginEdit();
var fs = record.fields;
fs.each(function(f){

/* The original Ext code is:
var field = this.findField(f.name);
if(field){
record.set(f.name, field.getValue());
}
*/
// start the new code
var field = this.findField(f.name);
if(field){
// If this field has the mySavedValue config, get that value
if (field.mySavedValue!=undefined) {
var myFldValue = field.mySavedValue;
} else {
// Get the normal field value
var myFldValue = field.getValue();
}
// Set the value to the record
record.set(f.name, myFldValue);
// end new code
}
}, this);
record.endEdit();
return this;
}
});


So, for all form fields attached to a descendant for Ext.form.BasicForm, if there is a config option called (in this case) mySavedValue, use that value to update the database record instead of the usual one in the form field value.

As an extra, I am using this technique in conjunction with another override for displayOnly/readOnly (http://extjs.com/forum/showthread.php?p=267172) fields. That override allows you to set a field to readOnly and style it as you wish. If you are doing that you need to make the following extra step. The field in question is called "actualSecs" which, again, is stored as seconds but displayed as decimal hours.

So, add the following lines to the form load handler:


// Convert from seconds to decimal hours and set that value to the field.
frm.findField('actualSecs').setValue(Ext.secs2DecimalHoursFormat(task.data.actualSecs));
// Save the original value now (ie the seconds) since the field wont be edited and we dont need to convert
// it back to seconds in the save handler as we do for editable fields.
// You could do that there though if you wanted to.
frm.findField('actualSecs').mySavedValue = task.data.actualSecs;


Any comments and suggestions are most welcome.

EDIT: January 19th, 2009. Fixed a bug whereby a field.mySavedValue of integer 0 (in the override) wasnt being loaded since it was resolving to false! Whoops. Changed
if (field.mySavedValue) { to
if (field.mySavedValue!=undefined) {
My apologies.

Cheers,
Murray

mystix
29 Dec 2008, 5:39 PM
that doesn't look very extensible. you might want to check out the OOSubmit plugin instead:
http://extjs.com/forum/showthread.php?t=28491

it calls the Field's getValue() method when the form is serialized, as opposed to simply obtaining the value of the Field's associated <input> tag. this i believe should allow you to achieve the same results as what you've done while being easily extensible.

murrah
29 Dec 2008, 7:13 PM
@mystix

Thanks for that. Yes, I had a look at that and after reading all the posts and questions I decided to opt for (what seems to me) a simpler solution to my particular problem. Having said that, when I have more time I will revisit it and test it.

Thanks again,
Murray

murrah
19 Jan 2009, 12:29 AM
If you are watching this post, please see the first post for a bug fix.

Cheers,
Murray