-
22 Mar 2012 11:56 AM #21
So in 4.1 RC1, a method Model.getData(boolean) was added. Passing a value of true will correctly call the getAssociatedData and return a complete object graph.
However, upon further inspection of the Ext.data.writer.Writer.getRecordData() function, I see they are not making use of this but are instead only iterating over the non-association fields of the model object. I see no way of indicating to the Writer that it should utilize Model.getData(). I think as a default that this is the correct behavior since more often then not you do not want to return a complete object graph but instead persist the associated models independently. But we still need a means of passing an option such that we can indicate we DO want it to do this.
I think this is an absolute necessity and I'm kind of shocked ExtJS has gone this far without something being done about this. It's things like this that make me desperately miss Backbone.js.
-
23 Mar 2012 6:00 AM #22
If anyone is interested, I solved this by making a custom Writer that is almost identical to the original Json writer but utilizes the new getData() method on Models for retrieving data to be written rather than just iterating over the fields. Then anytime you define a proxy on a model/store, if you wish for it to use this writer you just define it in the proxy config. See below.
Defines the custom Writer:
Then we add it to our proxy config:Code:Ext.define('Ext.data.writer.DeepJson', { extend:'Ext.data.writer.Json', getRecordData:function (record, operation) { var isPhantom = record.phantom === true, writeAll = this.writeAllFields || isPhantom, nameProperty = this.nameProperty, fields = record.fields, data = {}, changes, name, field, key; if (writeAll) { // This is the branch that has been changed from the original Json Writer data = record.getData(true); } else { changes = record.getChanges(); for (key in changes) { if (changes.hasOwnProperty(key)) { field = fields.get(key); name = field[nameProperty] || field.name; data[name] = changes[key]; } } } if (isPhantom) { if (operation && operation.records.length > 1) { data[record.clientIdProperty] = record.internalId; } } else { data[record.idProperty] = record.getId(); } return data; } });
Doing it this way you still maintain the default behavior of having to persist associations independently, but now have the option of utilizing an entire graph in the event you have something abnormally large where you may not want to submit 100's of requests to the back end.Code:proxy:{ type:'rest', autoAbort:false, url:'api/graph', reader:{ type:'json' }, writer:Ext.create('Ext.data.writer.DeepJson') }
-
26 Mar 2012 5:09 AM #23
Trying your class, I get this error:
Uncaught TypeError: Cannot read property 'persist' of undefined
Ext.define.afterEdit - ext-all-debug.js:46945
Ext.define.callStore - ext-all-debug.js:47942
Ext.define.afterEdit - ext-all-debug.js:47917
Ext.define.set - ext-all-debug.js:47590
Ext.define.insert- ext-all-debug.js:49114
Ext.define.add- ext-all-debug.js:49173
Ext.define.onValidateClick - liste.js:547
Ext.define.fireHandler- ext-all-debug.js:78194
Ext.define.onClick- ext-all-debug.js:78184
(anonymous function)
Ext.apply.createListenerWrap.wrap- ext-all-debug.js:897
-
26 Mar 2012 7:15 AM #24
I'm not doing anything with "persist", I'm merely modifying which fields are collected for the request. A la, the following snippet from the original Ext.data.writer.Writer:
has now become the following:Code:if (writeAll) { fLen = fieldItems.length; for (f = 0; f < fLen; f++) { field = fieldItems[f]; if (field.persist) { name = field[nameProperty] || field.name; data[name] = record.get(field.name); } } } else {...
If you are getting the above errors I'm going to guess that you have problems elsewhere or in how/where you are defining the new writer, but I can't help you without seeing any code of your own.Code:if (writeAll) { data = record.getData(true); } else {...
-
26 Mar 2012 11:43 PM #25
After searching a while, the solutions chrisface and cstrong have provided didn't work with ExtJS and record insertion.
So what I've done (and I think it's a bit safer) is calling first the parent's method, then after, add to the result the "hasMany" associations (if there are ones).
Here's my code, which works flawlessly. Please feel free to comment or to suggest:
Code:var ExtDataWriterJsonOriginal_getRecordData = Ext.data.writer.Json.prototype.getRecordData; Ext.data.writer.Json.override({ {*/* * This function overrides the default implementation of * json writer. Any hasMany relationships will be submitted * as nested objects */*} getRecordData: function(record) { var me = this, i, association, childStore, data = {}; data = ExtDataWriterJsonOriginal_getRecordData(record); /* Iterate over all the hasMany associations */ for (i = 0; i < record.associations.length; i++) { association = record.associations.get(i); if (association.type == 'hasMany') { data[association.name] = []; childStore = eval('record.'+association.name+'()'); //Iterate over all the children in the current association childStore.each(function(childRecord) { //Recursively get the record data for children (depth first) var childData = this.getRecordData.call(this, childRecord); if (childRecord.dirty | childRecord.phantom | (childData != null)){ data[association.name].push(childData); record.setDirty(); } }, me); } } return data; } });
-
30 Mar 2012 6:54 AM #26
Here's my code, which works flawlessly.
This is for 4.0.x or 4.1?
What about deleted records?
Original chrisface's code added deleted records with new field called "forDeletion".
Regards.UI: Sencha Architect 2.x / ExtJS 4 MVC
Server side: EJB 3.1 / CDI / JPA 2 / JAX-RS / JasperReports
Application Server: Glassfish 3.1.x
Databases: Oracle 10g & 11g / DB2 9 & 10 / Firebird 2.5
If you like my answer please vote!
-
30 Mar 2012 1:17 PM #27
The other didn't work for insertion with both Ext 4.0 and Ext 4.1, whereas my solution works for both.
But I still haven't tested yet deletion. I'll tell you.
-
10 Apr 2012 1:24 AM #28
As for deleted records, I just send the whole "current" records, which implies deletion then re-write of records.
It's acceptable in all the situations where there's a very few recursive nested hasMany relationship (usually no recursive). But you're right, I should mention it.
In my case it's perfect and works like a charm, and it may help others.
Maybe someone could change my code just to add deleted record (or something).
-
28 Jul 2012 9:39 PM #29
Has this been fixed?
Has this been fixed?
I'm having trouble writing to the server anything with association.
Also nested items that have only been mapped (not associated):
like:
{
test: {
auto: {
users: 40;
delay: 60;
}
}
}
When I map it fir the reader as:
{name: 'autoUsers', mapping: 'auto.users', type: 'number'},
{name: 'autoDelay', mapping: 'auto.delay', type: 'number'}
The writer writes the submitted ajax as :
{
autoUsers: 40;
autoDelay: 60;
}
But I need it to be returned in the same way that he got it.
Any help?
-
28 Jul 2012 10:17 PM #30
Use nameProperty: mapping config for the writer - see docs


Reply With Quote