-
13 Nov 2012 2:49 AM #41
Thx again flanders, but I dont find the right code position to do so.
I find a solution that works for my problem. I add a listener to the master store which adds a datachange event to all childstores.
MikeCode:listeners: { load: { fn: function(store,aRecords) { var i, j, association, childStore,record; for (j = 0; j < aRecords.length; j++) { for (i = 0; i < aRecords[j].associations.length; i++) { record = aRecords[j]; association = record.associations.get(i); if (association.type == 'hasMany') { childStore = eval('record.'+association.name+'()'); childStore.addListener( 'datachanged', function(){record.store.sync();} ); } } } } } },
-
13 Feb 2013 2:57 PM #42
DeepJson writer
DeepJson writer
This still seems to be an issue in the current version available to me: 4.1.1a. Thanks to Chrisface and others on this thread for the helpful feedback. Using Chrisface's code and modifying it with feedback & fixes from others, I came up with the extended class below, which I post here in case it saves anyone else some time:
Code:Ext.define('MetaTools.lib.data.writer.DeepJson', { extend: 'Ext.data.writer.Json', getRecordData: function (record, operation) { //Setup variables var me = this, i, association, childStore, data; data = me.callParent(arguments); //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] = null; childStore = record[association.storeName]; //Iterate over all the children in the current association childStore.each(function (childRecord) { if (!data[association.name]) { data[association.name] = []; } //Recursively get the record data for children (depth first) var childData = this.getRecordData.call(this, childRecord); /* * If the child was marked dirty or phantom it must be added. If there was data returned that was neither * dirty or phantom, this means that the depth first recursion has detected that it has a child which is * either dirty or phantom. For this child to be put into the prepared data, it's parents must be in place whether * they were modified or not. */ if (childRecord.dirty || childRecord.phantom || (childData != null)) { data[association.name].push(childData); record.setDirty(); } }, me); /* * Iterate over all the removed records and add them to the preparedData. Set a flag on them to show that * they are to be deleted */ Ext.each(childStore.removed, function (removedChildRecord) { //Set a flag here to identify removed records removedChildRecord.set('forDeletion', true); var removedChildData = this.getRecordData.call(this, removedChildRecord); data[association.name].push(removedChildData); record.setDirty(); }, me); } } //Only return data if it was dirty, new or marked for deletion. if (record.dirty || record.phantom || record.get('forDeletion')) { return data; } return null; } });
-
26 Feb 2013 8:40 AM #43
Not working
Not working
Anthony.jd, for some reason your code isn't working for me. Specifically this piece of code (it's returning null), however the childRecord object does have the correct data.
var childData = this.getRecordData.call(this, childRecord);
-
27 Feb 2013 9:36 AM #44
Hi Jose,
Just from quickly scanning through the class, it looks like it would return null, "Only return data if it was dirty, new or marked for deletion," so if your record was neither new nor deleted nor dirty (edited), then this code would return null. It is designed to only return data that has changed and therefore needs to be synced with its remote source.
If you wanted it to return all data regardless of its status, you could alter the last few lines, replacing
with simply:Code://Only return data if it was dirty, new or marked for deletion. if (record.dirty || record.phantom || record.get('forDeletion')) { return data; } return null;
Code:return data;
-
12 Apr 2013 3:05 AM #45
hi chrisface,
Thanks for sharing your code. I have a doubt
Will it take care of multiple relationship?
Combination of hasOne & hasMany?
-
12 Apr 2013 3:07 AM #46
-
17 Apr 2013 6:55 PM #47
Any ideas on how to configure json reader to handle deepjson response from model.save() or store.sync()?
I have deepjson writer functional and working. Server receives all data, creates, updates, deletes as necessary ... And responds with the same data structure as it received, except that phantom records now have IDs, creation dates are there, and maybe some other parameters are present that are set on the server when record is first created.
So my question is ... how do you apply data returned from deepjson writer to the existing data and mark all those records !dirty and !phantom? Is json reader even capable of doing that? Will store.sync() take care of everything if readers are set up properly? If yes, how to configure reader?
I guess I'll have to go deep into source code ... :|
-
14 May 2013 3:33 PM #48
Any comments from Sencha support on this issue. Handling change tracking using associated data, ie form has parent store and associated data store and store.save is for parent. So it only tracks parent fields dirty and not associated. Others have manually coded to handle some of this, but really I would think by now using 4.2 this would be built in?
-
14 May 2013 4:06 PM #49
http://docs.sencha.com/extjs/4.2.0/#...ientIdProperty
I think that if you set clientIdProperty: 'clientId' on Ext.data.Model and then return clientId parameter in the response object together with newly assigned idProperty, the framework should able to figure out which records are new and which phantom record to they belong to, even for deeply nested responses.
Response should look something like this:
I'm not 100% sure, it was very late when I tested it, so maybe you can give it a try and confirm this. Hopefully I'll find some time this week to thoroughly test this.Code:{ id: 123, children: [ {id: 123, clientId: -1, name: 'name1', ...}, {id: 124, clientId: -2, name: 'name2', ...}, {...}, {...} ] }
As for sending all data, just create a custom json writer. In one of my projects, I have a model with multiple hasMany associations and they have hasMany who have hasMany ...
I just send the entire object graph with custom json writer, process data on server, and return complete object graph back. I know it's an overhead to send all data, but it works
Of course in the future I plan to send only modified/new data ...
The model association framework still needs some work, especially with reading/writing deeply nested data. And some more documentation with advanced examples wouldn't hurt. But I'm sure that Sencha team will improve this
-
15 May 2013 4:45 AM #50
I think I get the custom writer part, and have seen the examples here on how to implement. The problem I am having is just getting a simple combobox on an edit form that has its primary record data loaded via from.load from the grid or list view. The problem is 2 stores 1 that loads the primary record 1 that loads the data for the combobox, they are not linked, so for example when the form loads the data and I set the value of the combobox manually from the primary models associated data, when I change the value of the combobox the primary store is not marked as dirty and therefore does not sync when I try to save. Since no sync event fired I don't even get to the writer part.
In addition I am setting selected value of combobox manually but shouldn't this be automatic since I have association setup and valueField of combobox with the key id equal to key id of associated record? Tried using form.load twice once for primary and once for associated as I read some post that this may work, but it doesn't
Here is some code
Edit form list and edit functions
Associations are working hasOne between Contact and ContactType as I can useCode:list: function () { var mystore = this.getStore('Contacts') mystore.proxy.extraParams = { $expand: 'ContactType'}; mystore.load({ params: { }, callback: function(r,options,success) { // debugger; } //callback }); //store.load // mystore.proxy.extraParams = { $expand: 'ContactType'}; // var User = this.getContactModel(); // User.load(258, { // success: function (user) { // console.log("Loaded user 258: " + user.get('lastName')); // } // }); }, editContact: function (grid, record) { var store = this.getStore('ContactTypes'); store.load({ params: { }, callback: function(r,options,success) { // debugger; } //callback }); //store.load var view = Ext.widget('contactsedit'); var form = view.down('form') var combo = form.down('combobox'); // combo.store.add({id:3, name:'expert wanna-be'}); form.loadRecord(record); var mykey = record.getContactType().data.__KEY combo.setValue(mykey) // // debugger; // form.loadRecord(record.getContactType()); // debugger; // form.loadRecord(records.baseModel()); //form.loadRecords(records.getAt(0)); this will load your form with id & name // form.loadRecords(records.getAt(0).getterName(); //form.loadRecord(record); this.addnew = false },to get the associated ContactType data for Contact.Code:record.getContactType()
Edit view combobox snippet
Really I am a more than a bit frustrated this should be a simple task. I feel like I must be missing something major as this seems very difficult to achieve. I just want to have a simple grid view that a user clicks on a row, then edit view pops up with primary record fields set and a combobox that sets the associated records value and save back to server. This is my first time building an app with ExtJs, you guys who have already developed apps with Extjs, the scenario I am describing at least I think is very common, most basic add/edit with grid and edit form, nothing fancy.Code:{ xtype: 'combobox', fieldLabel: 'Contact Type', store: 'ContactTypes', valueNotFoundText: 'not found', displayField: 'name', valueField: '__KEY', typeAhead: true, queryMode: 'local', emptyText: 'Select a type...' }
How have you all accomplished this task?
Should I not use associations?
If not use associations, what is the best practice for this using Extjs 4.2 mvc, any working examples, I would so very much appreciate it!
Just to clarify, I have two tables Contact with basic fname and lname, then a ContactsType, this is just a lookup table, like a states or countries table. In fact I would add two more comboboxes just like ContactType with Countries and States as associated hasOne relations if I can get it working easily.
Really need some help, spent hours and hours reading forums, google, docs, ect. Trying different things here and there. One thing is I don't want to just hack this problem with my javascript. Gotta be a best practices example for this somewhere, right?
Sorry for the rant? Just beating my head against a brick wall right now........


Reply With Quote