PDA

View Full Version : Modifying a value created by convert:function



alexander.urban
18 Feb 2014, 10:10 AM
My old model was:


{ name: 'StartDate', type: 'date', dateFormat: 'Y-m-d H:i' },
{ name: 'EndDate', type: 'date', dateFormat: 'Y-m-d H:i' }

and changing EndDate worked like a charm. Now I use the model


{ name: 'StartDate', type: 'date', dateFormat: 'Y-m-d H:i' },
{ name: 'EndDateOrig', type: 'date', mapping:'EndDate', dateFormat: 'Y-m-d H:i' },
{ name: 'EndDate', type: 'date', convert: function(v,rec) {
if(rec.get('StartDate')==rec.get('EndDateOrig')) return Ext.Date.add(rec.get('EndDateOrig'),Ext.Date.MINUTE,5);
else return rec.get('EndDateOrig');
}},

and changing EndDate does not work. It seems as if it is always overwritten.

If I understand documentation correctly, this problem cannot be caused by my convert function in the model definition (though I would not know what else could cause this), because convert function is only used during store.load, not during record.set.

Please reassure me that I understood documentation correctly, so I can focus my mind on what else could be the problem.

skirtle
19 Feb 2014, 2:25 AM
The convert function is called in set, see the source:

http://docs.sencha.com/extjs/4.2.1/source/Model.html#Ext-data-Model-method-set

I believe this behaviour has changed, in older versions it wasn't called. It's somewhat naive as it works fine for convert functions for primitive types but not for more complex conversions. There has been talk of trying to remove the conversion when calling set but it's a difficult change to make without breaking backwards compatibility.

I occasionally use a mapping function instead of a convert function. The docs for this are very out of date but the mapping config can be used with a function and that will be called only during an initial read. The advice in the docs to use a convert function to achieve complex mappings is very out-dated as, for the reasons you've observed, it totally beaks calls to set.

alexander.urban
19 Feb 2014, 3:12 AM
Okay, then how would I use a mapping function to do what I want to achieve:

Modify the EndDate if I am loading the store (I only use load(), no loadRecords(), loaData(), loadRaw() or other load functions) for all records where EndDate is the same as StartDate.

(I know I always could use the onload listener and iterate over all records, but then I won't learn more about the workings of ExtJS ;) )

skirtle
19 Feb 2014, 3:41 AM
If I were you I'd start by reading the code in Json reader for handling mapping. The mapping function gets passed the data root and is expected to return the value (it's just a function equivalent of the string mappings), so you'd have to do all the calculating yourself. A bit of console logging in your own mapping function might help clarify the arguments if the code to Json reader is a bit opaque.

Trying to build odd dependencies between fields like this is hacky territory. Using a mapping might centralize it into the model but unless you read data into this model/store in multiple places I'm not convinced it's really any better than iterating over the store. Arguably iterating would be less of a bodge, it's just more difficult to avoid duplication.

There are a lot of other potential hook points for this, especially on the reader, but I can't think of a genuinely clean solution.

alexander.urban
20 Feb 2014, 4:36 AM
I read data into the store at more than one place - in fact, load() is even called from a different app running in an iframe inside my app. So I would have to listen to the store's datachanged event, and if it is fired and my function is called, I have to suspend the datachanged event, change the data inside the store, and resume the datachanged event. But during that time, data could be changed by other functions, not firing the event because my function is still running over the store. It's all a bit messy, you see... :D that's why I hoped to do it inside the model/store.

Overriding the reader's mapping function, that could be a nice way to do this as well... or I'll just override the load function...

But I guess it'll open the box of pandora, all warranty void...;)