Trying to figure out how to work with promises between routes and controllers


#1

Hi all! I’m trying to learn how to use a promise created in a route in a controller of the same route. I have a router that gets a model (opportunity) for the route, as well as another data source (candidates) that I would like to use. I would like to create computed properties in the controller that filters the candidates based on boolean properties. I’m new to Ember and not sure if I’m even fetching the candidates in the correct way, so please point me in the right direction if I’m not.

My route looks as follows:

//app/routes/ats/opportunties/show.js
import Ember from 'ember';

export default Ember.Route.extend({
  sessionUser: Ember.inject.service('session-user'),

  model: function(params){
    // get model from parent route
    let company = this.modelFor('ats.opportunities');
    return company.get('opportunities').findBy('slug', params.opportunity_slug);
  },

  setupController: function(controller, opportunity) {
    // get candidates for this opportunity and set it as candidates on controller
    this._super(controller, opportunity);
    this.store.query('candidate', { opportunity: opportunity.get('slug') }).then((candidates)=>{
      controller.set('candidates', candidates);
    });
  }
});

And in my controller, I’m trying to do the following:

//app/controllers/ats/opportunties/show.js
import Ember from 'ember';

export default Ember.Controller.extend({
  locked: Ember.computed('candidates.@each.unlocked', function() {
      return this.get('candidates').then(function(candidates){
      	candidates.filterBy('unlocked', false);
      });
    })
});

Then, I’m trying to reference locked in my show.hbs template:

<div>
    Candidates: {{locked}}
</div>

Probably not needed, but for extra info, my candidate model:

//app/models/candidate.js
import DS from 'ember-data';

export default DS.Model.extend({
	name: 				DS.attr('string'),
	email: 				DS.attr('string'),
	unlocked: 			DS.attr('boolean'),
});

Now, that doesn’t work because then the template renders, the promise has not yet been resolved. When using Ember inspector, I can access locked just fine when I wait until the promise was resolved. What is the Ember Way® to do this? Pleeeease be very detailed when explaining since I probably won’t have an idea what you’re talking about. :smile:


#2

You can wait for your model promises with Ember.RSVP.hash like this:

I think it will resolve your problem and I hope is self-explains…


#3

As @broerse alludes, I believe you should do all the querying/promise building in the model method. Since the promise resolved from that method determines when the route is “done”.

What’s less clear to me is how Ember.RSVP.hash will work since the candidate query is dependent on the opportunities query. Will something like this work?

export default Ember.Route.extend({
  model: function() {
    var store = this.store;
    return company.get('opportunities').findBy('slug', params.opportunity_slug).then(function(opportunity) {
      return store.query('candidate', { opportunity: opportunity.get('slug') })
    });
  }

But since it’s the same slug for candidates and opportunities, it seems like you could save some work with:

export default Ember.Route.extend({
  model: function() {
    var store = this.store;
    return Ember.RSVP.hash({
      candidates: store.query('candidates', {'slug', params.opportunity_slug}),
      opportunities: store.query('opportunities', {'slug', params.opportunity_slug})
    });
  }

#4

Awesome, thanks guys! Adding everything in the model with a RSVP hash does the trick. Didn’t realise that Ember waits for model promises to resolve before continuing.