0
votes

I'm using ember.js for a week and ran into a problem concerning ember-data and ember.js. I have a simple 1:N-relationship on a model called User. User hasMany Slots which are defined by a start_time and an end_time.

In a component which is called slots-per-day all slots of a given user are rendered filtered by day with the following js code:

  /* ... rest of component.js of slots-per-day ... */
  filteredSlots: Ember.computed('user', function() {
    let time = moment();
    return this.get('user.slots').filter( (slot) => {
      let left = moment(time).startOf('day');
      let right = moment(time).endOf('day');
      let start_time = moment(slot.get('start_time'));
      let end_time = moment(slot.get('end_time'));
      console.debug(slot.get('start_time'));

      return start_time.isBetween(left, right) || end_time.isBetween(left, right);
    });
  })
  /* ... rest of component.js of slots-per-day ... */

There are several problems I faced with different approaches:

  1. Using the code above the filteredSlots-property is only evaluated once. The underlying storage is in an undefined state, since the console.debug outputs undefined but the amount of slots is just right. So i guess ember-data has loaded the array for the slots, but forget to load the rest of data. If I do a transition to the same route all data is displayed properly and console.debug returns different moment.js-dates.

  2. If I add user.slots to the dependency list of that property, it is evaluated twice. Both evaluations lead to the same debug output as in (1): undefined.

  3. If I add [email protected]_time, the property is evaluated the amount of components on that page times the amount of slots (which is very slow). Despite the fact, that it is slow, it works and renders the data correctly.

So the question is: How do I preload all data in ember-data, before the components get rendered?

EDIT:

I also tried with promises:

  /* SlotRoute ... */    
  setupController(controller, model){
    this._super(controller, model);
    controller.set('time', this.get('time'));
    controller.set('users', model.users);
    controller.set('timeScope', this.get('timeScope'));
  },

  users: Ember.computed('time', function() {
    return this.store.query('user', {
      slots: {
        time: this.get('time').toString(),
        timeScope: this.get('timeScope')
      }
    });
  }),

  model(params) {
    return Ember.RSVP.hash({
      users: this.get('users'),
      slots: this.store.get('slots')
    });
  },
  /* ... */

No change in positions (1), (2) and (3) of the list above.

1

1 Answers

0
votes

Number 3 is the correct way to write up your computed property, especially with an async relationship. You will have to pay the price somewhere, if you want to pay it during transition you can use afterModel assuming you are fetching user using the model hook. You can also use afterModel/beforeModel of that particular route if it's loaded somewhere else.

The route

model(params){
  return this.store.find('user', 1);
},
afterModel(model, transition){
  return model.get('slots');
}

The route using some service

afterModel(model, transition){
  return this.get('someservice.user.slots');
}