Skip to content
Snippets Groups Projects
Commit 763da046 authored by LE GAC Renaud's avatar LE GAC Renaud
Browse files

Polish dbsvc service. It can process several records in create and update transactions.

In addition all exceptions are logged to the web2py ticket system.
Fix a bug in App.form.Panel.onStoreException and improve it.
parent bf35db37
No related branches found
No related tags found
No related merge requests found
...@@ -7,6 +7,7 @@ import re ...@@ -7,6 +7,7 @@ import re
from basesvc import BaseSvc from basesvc import BaseSvc
from converter import ROOT, SUCCESS, TOTAL from converter import ROOT, SUCCESS, TOTAL
from gluon.contrib import simplejson as json from gluon.contrib import simplejson as json
from gluon.storage import Storage
from helper import (encode_field, from helper import (encode_field,
decode_field, decode_field,
get_foreign_field, get_foreign_field,
...@@ -16,10 +17,10 @@ from helper import (encode_field, ...@@ -16,10 +17,10 @@ from helper import (encode_field,
FIELD_NOT_IN_DB = "the field '%s.%s' doesn't exist in the database." FIELD_NOT_IN_DB = "the field '%s.%s' doesn't exist in the database."
KEYWORD_MISSING = "The keyword '%s' is missing." KEYWORD_MISSING = "The keyword '%s' is missing."
RECORD_DELETED = "Record %s is deleted."
RECORD_INSERTED = "Record is inserted with id %i."
RECORD_NOT_IN_DB = "The record '%s' doesn't exist in the table %s." RECORD_NOT_IN_DB = "The record '%s' doesn't exist in the table %s."
RECORD_UPDATED = "Record %s is updated." RECORDS_DELETED = "Record(s) %s is deleted."
RECORDS_INSERTED = "Record(s) is inserted with id(s) %s."
RECORDS_UPDATED = "Record(s) %s is updated."
TABLE_NOT_IN_DB = "The table '%s' doesn't exist in the database." TABLE_NOT_IN_DB = "The table '%s' doesn't exist in the database."
TO_MANY_RECORDS = "To many records !!!" TO_MANY_RECORDS = "To many records !!!"
...@@ -134,54 +135,6 @@ class DbSvc(BaseSvc): ...@@ -134,54 +135,6 @@ class DbSvc(BaseSvc):
return eval(query, {}, {"db": self.environment['db']}) return eval(query, {}, {"db": self.environment['db']})
def _get_fields(self, arg):
"""Helper method to get fields and their values in order to
create or update a record. The dictionary arg contains the following
keys:
tablename
the name of the table in the database
dbFields
The list of table fields.
It also include pointing field resolving foreign keys.
[(table1, field1), (table1, field2), (table2, field3), ...]
records (ROOT)
List of dictionary containing the new / update values for field
as well as the identifier of the record to be updated (id)
Return a dictionary {fieldName: value, ...}
or {"success": False, "errors": {...}, ..} in case of validation errors
"""
fields = {}
table = arg['tableName']
# protection
if len(arg[ROOT]) > 1:
raise DbSvcException(TO_MANY_RECORDS)
# Remove fields in the record which do not belong to the table.
# The JsonStore send the foreign key and the the pointing field
# when manipulating table with foreign keys. the latter belongs
# to another table.
record = arg[ROOT][0]
for table_field in record:
tablename, fieldname = decode_field(table_field)
if tablename == table:
fields[fieldname.encode('utf8')] = record[table_field]
# Validate field contents
di = self._is_fields_values_valid(table, fields)
if di:
table_id = encode_field(table, 'id')
record[table_id] = ""
return {SUCCESS: False, "errors": di, ROOT: record}
return fields
def _get_record(self, table, id): def _get_record(self, table, id):
"""Helper function to get the record id in a form which can be decoded """Helper function to get the record id in a form which can be decoded
by the JsonReader running on the client side. Foreign key are resolved. by the JsonReader running on the client side. Foreign key are resolved.
...@@ -239,8 +192,76 @@ class DbSvc(BaseSvc): ...@@ -239,8 +192,76 @@ class DbSvc(BaseSvc):
raise DbSvcException(TABLE_NOT_IN_DB % table) raise DbSvcException(TABLE_NOT_IN_DB % table)
def _prepare_records(self, arg):
"""Helper method to prepare the records for their insertion
in the database (create or update).
The current transaction is defined in the dictionary arg.
It is associate to one table and can contain several records.
tablename
the name of the table in the database
dbFields
The list of table fields.
It also include pointing field resolving foreign keys.
[(table1, field1), (table1, field2), (table2, field3), ...]
records (ROOT)
List of dictionary containing the new / update values for field
as well as the identifier of the record to be updated (id)
The method removes fields in the record which do not belong to the
table since the JsonStore send the foreign key and the pointing field.
Pointing fields are not used here.
The method also validates values.
Return a Storage:
{
"errors": [None,...],
"records": [{TableField: value,...}, ..]
}
There is one to one correspondence between the errors
and the records lists. Error is None when fields are validated.
Otherwise the error is a dictionary:
{TableField: "error message", ...}
"""
data = Storage(errors=[], records=[])
table = arg['tableName']
for record in arg[ROOT]:
fields = {}
# Remove fields in the record which do not belong to the table.
# The JsonStore send the foreign key and the the pointing field
# when manipulating table with foreign keys. the latter belongs
# to another table.
for table_field in record:
tablename, fieldname = decode_field(table_field)
if tablename == table:
fields[fieldname.encode('utf8')] = record[table_field]
data.errors.append(None)
data.records.append(fields)
# Validate field contents
di = self._is_fields_values_valid(table, fields)
if di:
table_id = encode_field(table, 'id')
record[table_id] = ""
data.records[-1] = record
data.errors[-1] = di
return data
def create(self, arg): def create(self, arg):
"""Create a new record defined in arg. """Create new records defined in the transaction arg.
The dictionary arg contains the following keys: The dictionary arg contains the following keys:
tableName tableName
...@@ -252,35 +273,58 @@ class DbSvc(BaseSvc): ...@@ -252,35 +273,58 @@ class DbSvc(BaseSvc):
[(table1, field1), (table1, field2), (table2, field3), ...] [(table1, field1), (table1, field2), (table2, field3), ...]
records (ROOT) records (ROOT)
A dictionary containing the update values for field A list of dictionary containing the new values for fields
as well as the identifier of the record to be updated (id) as well as the identifier of the record to be updated (id)
Return a dictionary with status, message and the update row: Return a dictionary with status, message and the update row:
{success: True, msg: 'blalbla', records:{TableId:xx,....}}
{
success: True,
msg: 'blalbla',
records: [{TableId: xxx,....}, ...]
}
When at least a field value is not validated, abort the full transaction
and return a dictionary with the error messages for the first bad record:
{
success: False,
errors: {TableField: error message, ..},
records:{TableField: xxx, ...}
}
""" """
self.dbg("Start DbSvc.create") self.dbg("Start DbSvc.create")
self._check_request(arg) self._check_request(arg)
fields = self._get_fields(arg) data = self._prepare_records(arg)
if SUCCESS in fields and fields[SUCCESS] == False: # Abort the full transaction if at least one record is in error
return fields for error in data.errors:
if error:
# insert new record i = data.errors.index(error)
table = arg['tableName'] return {SUCCESS: False, "errors": error, ROOT: data.records[i]}
id = self.environment['db'][table].insert (**fields)
# return the complete record # insert new records
# mandatory, since this is the one which is display in the grid. ids, table, records = [], arg['tableName'], []
record = self._get_record(table, id) for fields in data.records:
self.dbg("End DbSvc.create.", RECORD_INSERTED % id) id = self.environment['db'][table].insert (**fields)
return {SUCCESS: True, 'msg': RECORD_INSERTED % id, ROOT: record}
# return the complete record
# mandatory to display the new record in the grid.
record = self._get_record(table, id)
ids.append(str(id))
records.append(record)
txt = ', '.join(ids)
self.dbg("End DbSvc.create.", RECORDS_INSERTED % txt)
return {SUCCESS: True, 'msg': RECORDS_INSERTED % txt, ROOT: records}
def destroy(self, arg): def destroy(self, arg):
"""Destroy the record defined in arg. """Destroy the record defined in the transaction arg.
The dictionary arg contains the following keys: The dictionary arg contains the following keys:
tableName tableName
...@@ -294,8 +338,22 @@ class DbSvc(BaseSvc): ...@@ -294,8 +338,22 @@ class DbSvc(BaseSvc):
records (ROOT) records (ROOT)
A list with id numbers A list with id numbers
Return a dictionary with status, message and id of the deleted row: Return a dictionary with status, message and ids of the deleted row:
{success: True, msg: 'blalbla', records:{TableId:xx}}
{
success: True,
msg: 'blalbla',
records:[{TableId:xx}, ..]
}
When at least one record does not exist, abort the full transaction
and return a dictionary with the error messages for the first bad record:
{
success: False,
msg: 'blalbla',
records:{TableId:xx}
}
""" """
self.dbg("Start DbSvc.destroy") self.dbg("Start DbSvc.destroy")
...@@ -303,24 +361,30 @@ class DbSvc(BaseSvc): ...@@ -303,24 +361,30 @@ class DbSvc(BaseSvc):
self._check_request(arg) self._check_request(arg)
db = self.environment['db'] db = self.environment['db']
table = arg['tableName'] ids, table, records = [], arg['tableName'], []
table_id = encode_field(table, 'id') table_id = encode_field(table, 'id')
# Abort the transaction is at least one record does not exists
for id in arg[ROOT]: for id in arg[ROOT]:
if not db[table][id]: if not db[table][id]:
return {"success": False, txt = RECORD_NOT_IN_DB % (id, table)
"msg": RECORD_NOT_IN_DB % (id, table), return {"success": False, "msg": txt, ROOT: {table_id: id}}
ROOT: {table_id: id}}
# delete records
for id in arg[ROOT]:
del db[table][id] del db[table][id]
ids.append(str(id))
records.append({table_id: id})
txt = ', '.join(ids)
self.dbg("End DbSvc.destroy") self.dbg("End DbSvc.destroy")
return {"success": True, "msg": RECORD_DELETED % id, ROOT: {table_id: id}} return {"success": True, "msg": RECORDS_DELETED % txt, ROOT: records}
def read(self, arg): def read(self, arg):
"""Read the content of a table as specified in the arg dictionary. """Read the content of a table as specified in the transaction arg.
The latter contains the following keys: The arg dictionary contains the following keys:
tableName tableName
name of the database table name of the database table
...@@ -350,7 +414,11 @@ class DbSvc(BaseSvc): ...@@ -350,7 +414,11 @@ class DbSvc(BaseSvc):
dir dir
The method return a list of records: The method return a list of records:
{success: True, records: [{TableField: value, ...}, {...}, ...], ...}
{
success: True,
records: [{TableField: value, ...}, ...]
}
""" """
self.dbg("Start DbSvc.read") self.dbg("Start DbSvc.read")
...@@ -404,8 +472,8 @@ class DbSvc(BaseSvc): ...@@ -404,8 +472,8 @@ class DbSvc(BaseSvc):
def update(self, arg): def update(self, arg):
"""Update a record according to the arg dictionary. """Update records defined in the transaction arg.
The latter contains the following keys: The arg dictionary contains the following keys:
tableName tableName
the name of the table in the database the name of the table in the database
...@@ -416,30 +484,54 @@ class DbSvc(BaseSvc): ...@@ -416,30 +484,54 @@ class DbSvc(BaseSvc):
[(table1, field1), (table1, field2), (table2, field3), ...] [(table1, field1), (table1, field2), (table2, field3), ...]
records (ROOT) records (ROOT)
A dictionary containing the update values for field A list of dictionary containing the update values for field
as well as the identifier of the record to be updated (id) as well as the identifier of the record to be updated (id)
Return a dictionary with status, message and the update row: Return a dictionary with status, message and the update row:
{success: True, msg: 'blalbla', records:{TableId:xx,...}}
{
success: True,
msg: 'blalbla',
records: [{TableId: xxx,....}, ...]
}
When at least a field value is not validated, abort the full transaction
and return a dictionary with the error messages for the first bad record:
{
success: False,
errors: {TableField: error message, ..},
records:{TableField: xxx, ...}
}
""" """
self.dbg("Start DbSvc.update.") self.dbg("Start DbSvc.update.")
self._check_request(arg) self._check_request(arg)
fields = self._get_fields(arg) data = self._prepare_records(arg)
if SUCCESS in fields and fields[SUCCESS] == False: # Abort the full transaction if at least one record is in error
return fields for error in data.errors:
if error:
i = data.errors.index(error)
return {SUCCESS: False, "errors": error, ROOT: data.records[i]}
# the client send modified fields only # update records
# update the database accordingly ids, table, records = [], arg['tableName'], []
id = fields['id'] for fields in data.records:
table = arg['tableName']
self.environment['db'][table][id] = fields
# return the complete record # the client send modified fields only
# mandatory, since this is the one which is display in the grid. # update the database accordingly
record = self._get_record(table, id) id = fields['id']
self.environment['db'][table][id] = fields
# return the complete record
# mandatory to display the new record in the grid.
record = self._get_record(table, id)
ids.append(str(id))
records.append(record)
txt = ', '.join(ids)
self.dbg("End DbSvc.update.") self.dbg("End DbSvc.update.")
return {SUCCESS: True, "msg": RECORD_UPDATED % id, ROOT: record} return {SUCCESS: True, "msg": RECORDS_UPDATED % txt, ROOT: records}
...@@ -2,6 +2,9 @@ ...@@ -2,6 +2,9 @@
HEAD HEAD
- DirectSvc exceptions are logged in the ticket system. - DirectSvc exceptions are logged in the ticket system.
- Polish dbsvc service which can now process several records
in create and update transactions.
- Fix a bug and improve App.form.Panel.onStoreException.
0.4.10.1 (Dec 2012) 0.4.10.1 (Dec 2012)
- Bug fixed - Bug fixed
......
/** /**
* The FormPanel is an Ext.form.formPanel with an App.data.DirectStore. * The FormPanel is an Ext.form.formPanel with an App.data.DirectStore.
* It comes with two button 'Action' and 'Reset' and a set of method to * It comes with two button 'Action' and 'Reset' and a set of method to
* create, duplicate, destroy and update record in the direct store. * create, duplicate, destroy and update record in the direct store.
* *
* This object can be used as a classic form, a row editor for a grid, * This object can be used as a classic form, a row editor for a grid,
* a record browser, .... * a record browser, ....
* *
* The action associated to the button is set via the setAction method. * The action associated to the button is set via the setAction method.
* the create action is set by default. * the create action is set by default.
* *
* The type of this component is xform. * The type of this component is xform.
* *
* @extends Ext.form.FormPanel * @extends Ext.form.FormPanel
* @version * @version
* *
*/ */
Ext.namespace('App.form'); Ext.namespace('App.form');
...@@ -24,7 +24,7 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -24,7 +24,7 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
* The store has to be defined since the actions rely on it. * The store has to be defined since the actions rely on it.
*/ */
store: null, store: null,
/** /**
* Predefined configuration options * Predefined configuration options
*/ */
...@@ -42,13 +42,13 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -42,13 +42,13 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
defaultType: 'textfield', defaultType: 'textfield',
frame: true, frame: true,
monitorValid: true, monitorValid: true,
/** /**
* private attribute to keep track of current action parameters * private attribute to keep track of current action parameters
*/ */
currentAction: null, currentAction: null,
currentRecord: null, currentRecord: null,
/** /**
* private attributes for internationalization * private attributes for internationalization
*/ */
...@@ -57,29 +57,29 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -57,29 +57,29 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
textDuplicate: 'Duplicate', textDuplicate: 'Duplicate',
textReset: 'Reset', textReset: 'Reset',
textUpdate: 'Update', textUpdate: 'Update',
/** /**
* private method require by the ExtJs component model * private method require by the ExtJs component model
*/ */
initComponent: function () { initComponent: function () {
// helper function to reset the form // helper function to reset the form
// the scope is Ext.data.BasicStore // the scope is Ext.data.BasicStore
function resetForm() { function resetForm() {
this.reset(); this.reset();
} }
// construct the underlying class. DON'T MOVE // construct the underlying class. DON'T MOVE
App.form.FormPanel.superclass.initComponent.call(this); App.form.FormPanel.superclass.initComponent.call(this);
// button events listeners // button events listeners
this.buttonAction.on('click', this.doAction, this); this.buttonAction.on('click', this.doAction, this);
this.buttonReset.on('click', resetForm, this.getForm()); this.buttonReset.on('click', resetForm, this.getForm());
// link the form to the data store // link the form to the data store
this.store = App.getStore(this.store); this.store = App.getStore(this.store);
this.store.on('exception', this.onStoreException, this); this.store.on('exception', this.onStoreException, this);
this.store.on('write', resetForm, this.getForm()); this.store.on('write', resetForm, this.getForm());
// set the default action: create // set the default action: create
this.setAction('create'); this.setAction('create');
...@@ -91,9 +91,9 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -91,9 +91,9 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
* @param {Object} boolean * @param {Object} boolean
*/ */
disableFields: function (bool) { disableFields: function (bool) {
var form = this.getForm(); var form = this.getForm();
form.items.each(function (field) { form.items.each(function (field) {
field.setDisabled(bool); field.setDisabled(bool);
}); });
...@@ -110,33 +110,33 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -110,33 +110,33 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
var form = this.getForm(), var form = this.getForm(),
newRecord; newRecord;
if (!form.isValid()) { if (!form.isValid()) {
return; return;
} }
if (!this.store) { if (!this.store) {
throw new Error('the store is undefined !!!'); throw new Error('the store is undefined !!!');
} }
switch (this.currentAction) { switch (this.currentAction) {
case 'create': case 'create':
newRecord = new this.store.recordType(); newRecord = new this.store.recordType();
this.updateRecord(newRecord); this.updateRecord(newRecord);
this.store.add(newRecord); this.store.add(newRecord);
break; break;
case 'destroy': case 'destroy':
this.store.remove(this.currentRecord); this.store.remove(this.currentRecord);
break; break;
case 'duplicate': case 'duplicate':
newRecord = new this.store.recordType(); newRecord = new this.store.recordType();
this.updateRecord(newRecord); this.updateRecord(newRecord);
this.store.add(newRecord); this.store.add(newRecord);
break; break;
case 'update': case 'update':
this.currentRecord.beginEdit(); this.currentRecord.beginEdit();
this.updateRecord(this.currentRecord); this.updateRecord(this.currentRecord);
...@@ -144,29 +144,29 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -144,29 +144,29 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
break; break;
} }
if (this.store.autoSave === false) { if (this.store.autoSave === false) {
this.store.save(); this.store.save();
} }
}, },
/** /**
* Private method to hardreset the form. * Private method to hardreset the form.
* *
* The reset method resets the field value to the originally loaded. * The reset method resets the field value to the originally loaded.
* *
* The hardreset erases the originally loaded values and reset the form. * The hardreset erases the originally loaded values and reset the form.
* Hardreset is required to clean form in sequence like update, create,... * Hardreset is required to clean form in sequence like update, create,...
* It handle properly default value for combobox. * It handle properly default value for combobox.
* *
*/ */
hardReset: function () { hardReset: function () {
var form = this.getForm(); var form = this.getForm();
form.items.each(function (field) { form.items.each(function (field) {
field.originalValue = Ext.value(field.initialConfig.value, ''); field.originalValue = Ext.value(field.initialConfig.value, '');
field.setValue(field.originalValue); field.setValue(field.originalValue);
}); });
}, },
/** /**
* Handler to process store exception * Handler to process store exception
* the scope of this function is App.form.FormPanel * the scope of this function is App.form.FormPanel
...@@ -184,52 +184,67 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -184,52 +184,67 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
field, field,
fieldName, fieldName,
form = this.getForm(), form = this.getForm(),
msg, msg = '',
records; records;
// mark fields invalid switch (type) {
for (fieldName in response.errors) {
if (response.errors.hasOwnProperty(fieldName)) { // invalid response from the server, HTTP 400, 500
field = form.findField(fieldName); // inform the user
field.markInvalid(response.errors[fieldName]); case 'response':
} Ext.Msg.alert('Error...', 'Internal server error.');
} break;
// report the exception to the user // valid answer from the server, HTTP 200
// The first case is when the server replies // something went wrong in the server validation process, ...
if (type === 'remote' && response.xhr.status !== 200) { case 'remote':
msg = response.xhr.statusText.toLowerCase() + '. '; // mark fields invalid
for (fieldName in response.errors) {
// remove the new records from the store if (response.errors.hasOwnProperty(fieldName)) {
if (action === 'create') { field = form.findField(fieldName);
records = this.store.getModifiedRecords(); field.markInvalid(response.errors[fieldName]);
for (i=0; i < records.length; i += 1) {
this.store.remove(records[i]); msg += response.errors[fieldName];
} msg += '<br>';
}
msg += '<br><br>'; }
msg += 'The record was removed from the internal storage.';
} // Keep the store in synchronization with the database
// remove the new records from the store
msg += 'The database is not modified.'; records = arg;
Ext.Msg.show({ switch (action) {
title: action + ' the record failed', case 'create':
msg: msg, for (i=0; i < records.length; i += 1) {
buttons: Ext.Msg.OK, this.store.remove(records[i]);
icon: Ext.Msg.ERROR, }
width: 300
}); msg += 'The new record(s) is removed from the internal storage.<br>';
break;
case 'update':
for (i=0; i < records.length; i += 1) {
records[i].reject();
}
msg += 'The update record(s) is revert to its original values.<br>';
break;
}
msg += 'The database is not modified.';
// inform the user
Ext.Msg.alert(action + ' failed...', msg);
break;
} }
}, },
/** /**
* Public method to set the action associated to the form. * Public method to set the action associated to the form.
* The record is load into the form and the text of the button is * The record is load into the form and the text of the button is
* properly set. Understood action are: create, destroy, duplicate, * properly set. Understood action are: create, destroy, duplicate,
* update and view. * update and view.
* @param {Object} action * @param {Object} action
* @param {Object} record * @param {Object} record
...@@ -239,27 +254,27 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -239,27 +254,27 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
var form = this.getForm(), var form = this.getForm(),
table, table,
tableId; tableId;
this.buttonReset.show(); this.buttonReset.show();
this.buttonAction.show(); this.buttonAction.show();
this.disableFields(false); this.disableFields(false);
this.currentAction = action; this.currentAction = action;
this.currentRecord = record; this.currentRecord = record;
switch (action) { switch (action) {
case 'create': case 'create':
this.hardReset(); this.hardReset();
this.buttonAction.setText(this.textCreate); this.buttonAction.setText(this.textCreate);
break; break;
case 'destroy': case 'destroy':
this.buttonAction.setText(this.textDestroy); this.buttonAction.setText(this.textDestroy);
form.loadRecord(record); form.loadRecord(record);
break; break;
case 'duplicate': case 'duplicate':
this.buttonAction.setText(this.textDuplicate); this.buttonAction.setText(this.textDuplicate);
this.hardReset(); this.hardReset();
...@@ -268,12 +283,12 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -268,12 +283,12 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
delete record.data[tableId]; delete record.data[tableId];
form.loadRecord(record); form.loadRecord(record);
break; break;
case 'update': case 'update':
this.buttonAction.setText(this.textUpdate); this.buttonAction.setText(this.textUpdate);
form.loadRecord(record); form.loadRecord(record);
break; break;
case 'view': case 'view':
this.buttonReset.hide(); this.buttonReset.hide();
this.buttonAction.hide(); this.buttonAction.hide();
...@@ -282,7 +297,7 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -282,7 +297,7 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
break; break;
} }
}, },
/** /**
* Private method to update the selected record with the value of the form * Private method to update the selected record with the value of the form
* This method have been designed to handle foreign keys, date object, .... * This method have been designed to handle foreign keys, date object, ....
...@@ -292,13 +307,13 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -292,13 +307,13 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
var combo, var combo,
field, field,
fields = [], fields = [],
i, i,
items, items,
rec, rec,
value; value;
// get the list of dirty fields // get the list of dirty fields
items = this.findByType('field'); items = this.findByType('field');
for (i = 0; i < items.length; i += 1) { for (i = 0; i < items.length; i += 1) {
field = items[i]; field = items[i];
...@@ -307,7 +322,7 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -307,7 +322,7 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
} }
} }
// include dirty fields embedded in composite fields // include dirty fields embedded in composite fields
items = this.findByType('compositefield'); items = this.findByType('compositefield');
for (i = 0; i < items.length; i += 1) { for (i = 0; i < items.length; i += 1) {
items[i].items.eachKey(function(key, subfield) { items[i].items.eachKey(function(key, subfield) {
...@@ -318,17 +333,17 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -318,17 +333,17 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
// update the record // update the record
// take care of special treatment required by date and combobox // take care of special treatment required by date and combobox
for (i = 0; i < fields.length; i += 1) { for (i = 0; i < fields.length; i += 1) {
field = fields[i]; field = fields[i];
value = field.getValue(); value = field.getValue();
switch (field.getXType()) { switch (field.getXType()) {
// We convert the date object according to a string defined // We convert the date object according to a string defined
// by the Ext.form.DateField property format. // by the Ext.form.DateField property format.
// NOTE: by default in the json encoding, the date object // NOTE: by default in the json encoding, the date object
// is converted as string using iso format YYYY-MM-DDTHH:MM:SS. // is converted as string using iso format YYYY-MM-DDTHH:MM:SS.
// However, the string expected by the database depends on // However, the string expected by the database depends on
// the date type: date, datetime or time. The format of the // the date type: date, datetime or time. The format of the
// Ext.form.DateField, used by the interface, is defined in the // Ext.form.DateField, used by the interface, is defined in the
// property format. // property format.
...@@ -339,21 +354,21 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, { ...@@ -339,21 +354,21 @@ App.form.FormPanel = Ext.extend(Ext.form.FormPanel, {
} }
break; break;
// For foreign key, the record contains the valueField // For foreign key, the record contains the valueField
// as well as the displayField. The default action update // as well as the displayField. The default action update
// the valueField but note the display field. // the valueField but note the display field.
// The next lines append the displayField // The next lines append the displayField
case 'xcombobox': case 'xcombobox':
combo = field; combo = field;
rec = combo.findRecord(combo.valueField, combo.getValue()); rec = combo.findRecord(combo.valueField, combo.getValue());
record.set(combo.displayField, rec.get(combo.displayField)); record.set(combo.displayField, rec.get(combo.displayField));
break; break;
} }
record.set(field.getName(), value); record.set(field.getName(), value);
} }
} }
}); });
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment