If I have a record with an async hasMany relationship for example the events property on the User model defined in the code below.
App.User = DS.Model.extend({
name: DS.attr('string'),
events: DS.hasMany('event', { async: true })
});
App.Event = DS.Model.extend({
title: DS.attr('string'),
date: DS.attr('date')
});
And my server returns a payload that contains a link to the endpoint containing the list of events associated with this user.
{
id: 1,
name: 'user1',
links: {
events: '/user/1/events'
}
}
When I call userModel.reload() the list of events for this user is not re-requested.
I have put together a jsbin to demo my problem. In this jsbin the "Update Backend and Reload" button changes the state of the user record on my backend and reloads the user model. I had expected this to also re-request the list of events from the '/user/1/events' resource. The "Reset Relationships" is a hacky way to reset the events relation ship and causes the list of events to be re-requested.
http://emberjs.jsbin.com/bemaxaqa/1/edit
I would like to get confirmation if this is a valid bug or if my assumption here is off base. Thanks.
Funny, I ran into this exact same case yesterday and implemented something essentially identical to your resetRelationships method.
:+1: for the assumption that reloading a record would re-request async hasManys
Yes I noticed this as well. I have a form with some async child data which I save along with the parent. After saving the parent I want to refresh the child data to ensure I have all the newly allocated IDs. @bmac thanks for the solution but certainly agree that it would be nice to know why reload() doesn't at least get rid of cached relationship data.
See also #2002
Updates ??
This will now rerequest the records if the link changed, but not otherwise. Should it also do that if the link stays the same?
Just ran into this problem yesterday. Glad to see its underway. We would definitely need the associated records to be changed, even if the link is the same (which it most likely would be). Generally speaking, reloading an object should remove loaded associations, so its children would be reloaded as well.
Using the blog post/comment example, you may have a list of blog posts, and a post detail page that contains the async comments (via a links node). In this case, I'd like to reload the post every time as well as update its comments:
models/post.js
import DS from 'ember-data';
export default DS.Model.extend({
title: DS.attr('string'),
body: DS.attr('string'),
comments: DS.hasMany('comment', { async: true })
});
GET posts/123 JSON response
{
"post": {
"title": "First!",
"body":"Lorem dim sum",
"links": {
"comments": "http://localhost:3000/api/posts/123/comments"
}
}
}
routes/post.js
import Ember from 'ember';
export default Ember.Route.extend({
model: function(params) {
return this.store.find('post', params.user_id);
},
setupController: function(controller, model) {
model.reload();
controller.set('model', model);
}
});
This code re-gets the post model and replaces the cached post, but it doesn't currently re-get the comments.
If the url is the same, you can do
model.get('comments').reload() Is that good enough? You think we should be reloading the linked hasMany by default as well?
IMO reloading an object should unload its children, meaning that they would be reloaded automatically by default.=
@uberllama that would prevent you from rendering the object while it is reloading.
You can also imagine that if you have a wide relationships graph(imagine Facebook friends), that reloading 1 person would cause your entire app to reload.
Fair point. Ill do the manual reload. Cheers.
This is really turning into a problem for me. I have a tree with children, and what I need to do is to unload all nodes, and then fetch the structure again. (Children are async loaded self-referential hasMany). I can't manually trigger a reload for every level of children, since the structure is handed of to another component, that only accesses the children collection if a parent node is expanded. What happens is that the nodes think that the children are already fetched, and we end up with a "Cannot read property 'then' of undefined".
A related issue is also that when i unload all nodes, they are not purged from the store, but left in destroyed state.
One more thing, reloading an unloaded record fails. This is from ember-data 1.0 beta 11:
@method reload
@return {Promise} a promise that will be resolved with the record when the
adapter returns successfully or rejected if the adapter returns
with an error.
*/
reload: function() {
set(this, 'isReloading', true);
This first line fails since you can't set on a destroyed object....
Error: Assertion Failed: calling set on destroyed object
Ended up working around the issue by introducing a timestamp in the ID of the nodes. I.e. reloading the top-element worked, the links to children from that contains a timestamp. This way I get a unique part of the id for each load of the structure.
@afinne Would you have time to put together a simple js bin of your "unload all nodes, and then fetch the structure again" example? The unloaded nodes being left in the store in a destroyed state sounds like a bug somewhere...
This is an issue for me also.
In my case the children may have been added to the colletion and therefore simply doing something like this does not work.
shipment.get('shipmentVehicles').forEach(function(shipmentVehicle) {
//The problem here is that there may be additional shipmentVehicles added on the server side after the initial shipmentVehicles are fetched. The frontend will now know about them.
shipmentVehicle.reload();
});
I think we need a reloadTree() method or something.
+1 for reloadTree() or some other method to say "reload every single thing Ember knows about this model, including all relationships".
+1 we have reload for a single item... but we need also a reloadTree. We can have both.
+1 for reload of a single 'belongsTo' relationship.
+1 for reload of has_many relationships to avoid having to manually push those objects into the store.
Do we have any method to reload() a collection of models? Running a forEach loop on the collections is not the best way though. Thoughts?
For now, we can manually reload a hasMany, also the hasMany (via link) is automatically reloaded if the link is updated.
The reload of a belongsTo is currently possible using the ds.references flag https://github.com/emberjs/data/blob/3e32efe8d6c0a062df9fd8314229a2575ee596a7/tests/integration/relationships/belongs-to-test.js#L1193.
I'm not sure we want to trigger an automatic reload of all record's associations (it could end up reloading the entire graph)
For reloading a collection of records (other than a hasMany), for now, I don't see other way than calling records.invoke('reload'). I'm not sure, but I guess if some of the records are of the same type, the calls will be coalesced into one single request.
@bmac Does this issue has been discussed recently ? Maybe it could be closed now ?
I created a new gist for this issue based on my original gist. And I was able to get it to reload using the reference api for the relationship in Ember Data 2.9.
http://emberjs.jsbin.com/naciqabafu/1/edit?html,js,console,output
I'm going to close this issue. It seems like there is a worry that automatically reloading all of the relationships on a record might lead to a performance problem in an app.
Today the best way to reload a relationship is to call record.hasMany('relationshipName').reload() or record.belongsTo('relationshipName').reload() to reload a specific relationship or use the following code to reload all relationships.
record.eachRelationship(function(name, descriptor) {
record[descriptor.kind](name).reload();
});
I do think a nicer API for this specific problem would be useful to some people. Maybe this is something someone could experiment with in an Ember Addon?
Dear @bmac, do you think this is the better way?
And where? In didTransition() of the route maybe?
Before today I was thinking that Ember had a way similar to reload: true. Not this manually way.
What is the BEST BEST BEST way for performances?
My models are heavily edited and with many users coming in and out changing route.
@bmac and the state of reloading? For spinner and so on?
@bmac you're the best! Really not sure why all the async relationships wouldn't reload when I force the parent model to reload. Seems like they should to me.
Most helpful comment
I'm going to close this issue. It seems like there is a worry that automatically reloading all of the relationships on a record might lead to a performance problem in an app.
Today the best way to reload a relationship is to call
record.hasMany('relationshipName').reload()orrecord.belongsTo('relationshipName').reload()to reload a specific relationship or use the following code to reload all relationships.I do think a nicer API for this specific problem would be useful to some people. Maybe this is something someone could experiment with in an Ember Addon?