简体   繁体   中英

Ember not rendering component at first

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:

  • Image
  • Crop

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM