Saving objects that are linked hasMany relation with a single Store
We are using a main object (A) that has a hasMany relation with a list of B objects.
For the A object we have a store with specific url api for reading and for updating data.
I have to mention that we have this URL configured only in the Store object A.
When we use the .load() method on the A store we receive a json stream that will contain also a list of B objects and this objects are very well fetched in B list form A object.
After we modify A object and some of the related B objects, and after we call .sync() method on AStore object we discover that the related B objects are not present in the generated json stream, so are not sent to the server together with A object.
Do you have any idea how can I synchronize with a single call the main A objects(along with the list of B objects) with the server?
Thank you very much for any idea regarding this.
Missing something: how to mark parent record dirty when changes made to child store?
Many thanks to chrisface for the code posting.
As I understand it, the objective here is to read and write an object graph using only a single round trip each.
I think I am still missing one piece...
Let's pretend I am dealing with User and Post. User hasMany Post
I am showing the User information in one place, and I am displaying Post records in their own separate grid.
Now I add a new Post to the Post grid, and then call sync() on the User store.
Nothing happens. Why? Because the User record was never marked dirty even though a new Post object was added like so:
user.posts().add( {} ); // <-- this should mark the user instance dirty, but doesn't
I can fake it by adding a 'datachanged' listener or by manually:
user.setDirty();
I am thinking this linkage should be an option to set up in the hasManyAssociations createStore()
method, to enable this kind of behavior, thus reducing the number of round-trips to the server.
What am I missing?
Making changes to child record mark parent as dirty, and small fix for code post
chrisface thanks again for the updated posting.
Only issue I see is that belongsTo associations trigger null reference. I added a small fix to work around that issue.
I added an if condition directly underneath your for loop where you loop through the associations to check the type:
Code:
//Iterate over all the hasMany associations
for (i = 0; i < record.associations.length; i++) {
association = record.associations.get(i);
if (association.type == 'hasMany') { // <-- this avoids null reference issue
.....// rest of method goes here
}
I didn't grok your situation thoroughly, but I suspect you might be using a many-to-many approach (a join class), which might be why you didn't see the issue with belongsTo.
We have a one-to-many relationship, and the belongsTo association is quite helpful because, among other things, it automatically adds a reference to the parent model object inside the child.
We are namespacing our models, so we had to override several configuration parameters in order for the ext association code to generate reasonable getters and setters (otherwise you get nonsense like "Foo.models.MyModelBelongsToInstance" and "getFoo.model.Parent()" )
FWIW, here is the code I wrote to automatically mark the parent dirty when a child is modified, added, or deleted
Code:
associations : [
{
type : 'hasMany',
model : 'Foo.model.ChildOb',
name : 'childobs', // generates childobs() method
foreignKey : 'parent_id',
storeConfig : {
listeners: {
// Set parent object dirty if we added a new child.
add: function(store, records, index, opts) {
var obj = records[0]; // NOTE not fully general but works for our case!
if (obj.get('id') === 0) {
this.setParentDirty(obj.get('parent_id'));
}
},
// Set parent object dirty if we removed an existing child
remove: function(store, obj, index, opts) {
if (obj.get('id') != 0) {
obj.parent.setDirty();
}
},
// Set parent object dirty if we updated an existing child
update: function(store, obj, index, opts) {
if (obj.get('id') != 0) {
obj.parent.setDirty();
}
}
},
setParentDirty: function(parent_id) {
var store = Ext.data.StoreManager.lookup('Parents');
var pool = store.getById(parent_id);
if (parent) {
parent.setDirty();
}
}
}
},
Here is my child belongsTo association
Code:
associations: [
{
type : 'belongsTo',
model : 'Foo.model.Parent',
foreignKey : 'parent_id', // if not overridden you get 'Foo.model.Parent_id'
getterName : 'getParent', // if not overridden you get 'getFoo.model.Parent'
setterName : 'setParent', // if not overridden you get 'setFoo.model.Parent'
instanceName: 'parent' // if not overridden you get 'Foo.model.ParentBelongsToInstance'
}
]