I'm building an Ember app which uses quite a few components. I'm also using Bootstrap. I've got a layout with tabs, and inside the second tab (which is hidden by default), the component (which contains a list of models which have a hasMany
relationship with the main model) won't render.
I think I tracked this down to Ember Data resolving after the view is rendered, because if I click on another model of the list, these relations will show up.
Some info and details:
I have two main models:
An image can have many crops.
I have an Images/Index controller which has this function:
loadCrops: function() {
var self = this;
this.get('selectedImage').get('crops').then(function(crops) {
self.set('selectedImageCrops', crops);
});
}.on('model.isFulfilled')
I added this method because I tried to manually resolve the relationship and get the crops for the image loaded in a variable but I had no luck with this. I'm passing the variables like this:
{{image-crops image=selectedImage crops=selectedImageCrops}}
This is my Index route:
export default Ember.Route.extend({
model: function () {
return this.store.find('image');
},
setupController: function(controller, model, request) {
controller.set('model', model);
}
});
If anyone needs more details please, ask for them. Thank you all!
When you use function() {}.on()
you are telling Ember to execute that function when an event occurs. model.isFulfilled
isn't an event though but a property so you need to observe it instead and do a quick check within the method that it really has been fullfilled (so it won't trigger if the promise is restarted for example)
loadCrops: function() {
if(!this.get('model.isFulfilled')) {
return;
}
var self = this;
this.get('selectedImage').get('crops').then(function(crops) {
self.set('selectedImageCrops', crops);
});
}.observes('model.isFulfilled')
Also as a side note I would suggest that you use an ES6 arrow function (which retains the outer this
) instead of using var self = this
, it's make the code a bit nicer.
loadCrops: function() {
if(!this.get('model.isFulfilled')) {
return;
}
this.get('selectedImage').get('crops').then((crops) => {
this.set('selectedImageCrops', crops);
});
}.observes('model.isFulfilled')
Try changing to a computed property:
selectedImageCrops: function() {
return this.get('selectedImage.crops');
}.property('selectedImage')
What I did in the end was moving the code to load the crops to the route's model
, and returning an Ember.RSVP.hash
with both the images and the crops, and then assigning it to the controller:
export default Ember.Route.extend({
/**
* Returns an Image instances array
*
* @method model
* @return {Ember.RSVP.hash} Images & Crops
*/
model: function () {
return Ember.RSVP.hash({
images: this.store.find('image'),
crops: this.store.find('crop')
});
},
/**
* Takes care of setting the needed variables in the controller
*
* @method setupController
*/
setupController: function(controller, model, request) {
controller.set('model', model.images);
controller.set('crops', model.crops);
}
});
Then I added a helper function in the controller to get the current image's crops:
selectedImageCrops: function() {
return this.get('crops').filter((obj) => {
return obj.image === this.get('selectedImage');
})[0];
}.property("selectedImage")
Thanks to @Karl-Johan Sjögren for the tip on the arrow function!
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.