PDA

View Full Version : [FIXED-116] record.reject() not working



robmonie
23 Apr 2011, 3:26 AM
It appears that the reject() method on a record / model is not working. Looking at the code, this appears to be due to the fact that modifications to records are not being tracked when set('field', value) is called.

This is very easy to reproduce:

1. Retrieve an instance of a model from a store
2. Update one of the fields via the "set" method
3. Confirm that this change is not tracked in the 'modified' property of the record
4. Call record.reject()
5. Confirm that the record has not been reverted to the last 'commited' value as documented.


This makes validation on models useless if the user decides to leave without successfully committing a change as the change cannot be reverted to the last 'good' state. I can manage this via reloading from the server but that comes at a ux cost.

holdenmatt
2 Jun 2011, 6:54 PM
Yep, I noticed the same thing. Anyone have an update or fix?
If a user edits a model object and then cancels, I'd like to revert to the last committed state.

rdougan
3 Jun 2011, 2:37 PM
I've opened a bug report for this. Thanks.

holdenmatt
3 Jun 2011, 3:51 PM
Thanks.
I found a workaround for this by looking through the source code: calling model.setDirty() snapshots the current field values. Then if you make model changes, model.reject() reverts to the snapshot.

This isn't how I expected this to work from the docs -- so probably worth updating to code or the docs to be in sync.

edspencer
5 Jul 2011, 5:13 PM
Thanks for the report - this actually came up in Ext JS 4 too and has already been fixed there. I'm porting the fix over to Touch 1.1.x so it will be present in 1.1.1. In the meantime this should work for you:



Ext.override(Ext.util.Stateful, {
set: function(fieldName, value) {
var me = this,
fields = me.fields,
modified = me.modified,
convertFields = [],
field, key, i;

/*
* If we're passed an object, iterate over that object. NOTE: we pull out fields with a convert function and
* set those last so that all other possible data is set before the convert function is called
*/
if (arguments.length == 1 && Ext.isObject(fieldName)) {
for (key in fieldName) {
if (!fieldName.hasOwnProperty(key)) {
continue;
}

//here we check for the custom convert function. Note that if a field doesn't have a convert function,
//we default it to its type's convert function, so we have to check that here. This feels rather dirty.
field = fields.get(key);
if (field && field.convert !== field.type.convert) {
convertFields.push(key);
continue;
}

me.set(key, fieldName[key]);
}

for (i = 0; i < convertFields.length; i++) {
field = convertFields[i];
me.set(field, fieldName[field]);
}

} else {
if (fields) {
field = fields.get(fieldName);

if (field && field.convert) {
value = field.convert(value, me);
}
}

me[me.persistanceProperty][fieldName] = value;

if (field && field.persist && !me.isEqual(currentValue, value)) {
if (me.isModified(fieldName)) {
if (me.isEqual(modified[fieldName], value)) {
// the original value in me.modified equals the new value, so the
// field is no longer modified
delete modified[fieldName];
// we might have removed the last modified field, so check to see if
// there are any modified fields remaining and correct me.dirty:
me.dirty = false;
for (key in modified) {
if (modified.hasOwnProperty(key)){
me.dirty = true;
break;
}
}
}
} else {
me.dirty = true;
modified[fieldName] = currentValue;
}
}

if (!me.editing) {
me.afterEdit();
}
}
}
});

MegaloKef
28 Nov 2011, 9:19 AM
I have the same issue (reject() not working in Sencha Touch 1.1)

I tried overriding the set function as described here, but I don't think this is a fix meant for Touch, i get all kinds of undefined errors.
(for example:
field.persist is undefined
currentValue is undefined

Is anybody aware of any fix to the reject() issue that works with Sencha Touch?
thanks!

urk
7 Dec 2011, 6:13 AM
Hi,

This override works for me (don't worry about the number of lines, actually it's just two edited lines and an additional small function taken from the Sencha Touch 2 Developer Preview):


if (Ext.version == '1.1.1') {

// fix: modified records are not marked as dirty and therefore ignored on store sync
Ext.override(Ext.util.Stateful, {

/**
* Sets the given field to the given value, marks the instance as dirty
* @param {String|Object} fieldName The field to set, or an object containing key/value pairs
* @param {Mixed} value The value to set
*/
set: function(fieldName, value) {
var me = this,
fields = me.fields,
modified = me.modified,
convertFields = [],
field, key, i;

/*
* If we're passed an object, iterate over that object. NOTE: we pull out fields with a convert function and
* set those last so that all other possible data is set before the convert function is called
*/
if (arguments.length == 1 && Ext.isObject(fieldName)) {
for (key in fieldName) {
if (!fieldName.hasOwnProperty(key)) {
continue;
}

//here we check for the custom convert function. Note that if a field doesn't have a convert function,
//we default it to its type's convert function, so we have to check that here. This feels rather dirty.
field = fields.get(key);
if (field && field.convert !== field.type.convert) {
convertFields.push(key);
continue;
}

me.set(key, fieldName[key]);
}

for (i = 0; i < convertFields.length; i++) {
field = convertFields[i];
me.set(field, fieldName[field]);
}

} else {
if (fields) {
field = fields.get(fieldName);

if (field && field.convert) {
value = field.convert(value, me);
}
}
// *** added line ***
currentValue = me.get(fieldName);
me[me.persistanceProperty][fieldName] = value;

// *** edited line *** if (field && field.persist && !me.isEqual(currentValue, value)) {
if (!me.isEqual(currentValue, value)) {
if (me.isModified(fieldName)) {
if (me.isEqual(modified[fieldName], value)) {
// the original value in me.modified equals the new value, so the
// field is no longer modified
delete modified[fieldName];
// we might have removed the last modified field, so check to see if
// there are any modified fields remaining and correct me.dirty:
me.dirty = false;
for (key in modified) {
if (modified.hasOwnProperty(key)){
me.dirty = true;
break;
}
}
}
} else {
me.dirty = true;
modified[fieldName] = currentValue;
}
}

// fix
me.dirty = true;

if (!me.editing) {
me.afterEdit();
}
}
},

// *** added function ***
/**
* Checks if two values are equal, taking into account certain
* special factors, for example dates.
* @private
* @param {Object} a The first value
* @param {Object} b The second value
* @return {Boolean} True if the values are equal
*/
isEqual: function(a, b){
if (Ext.isDate(a) && Ext.isDate(b)) {
return a.getTime() === b.getTime();
}
return a === b;
}

});

};

Cheers,

Uwe