Christian Fazzini
Christian Fazzini

Reputation: 19713

Setting up a controller property after the model hook

I need to set a controller property after the model hook. I can think of two ways to do this:

model(params) {
  return this.store.findRecord('user', 1);
},

afterModel(model, transition) {
  model.get('profile').then(profile => {
    this.set('profile', profile);
  });
},

setupController(controller, model) {
  controller.set('model', model);
  controller.set('profile', this.get('profile'));
},

The other approach. i.e. skip setupController:

model(params) {
  return this.store.findRecord('user', 1);
},

afterModel(model, transition) {
  model.get('profile').then(profile => {
    this.controller.set('profile', profile);
  });
},

Both seem to work.

Are there any added advantages / disadvantages with either approach? Clearly, the latter is shorter. But does it feel "clean" to set the controller property in an afterModel hook?

EDIT: the relationship/association between user and profile is async.

Upvotes: 1

Views: 3095

Answers (2)

user663031
user663031

Reputation:

As another poster pointed out, you can access model.profile, but that won't work from code if profile is an async association:

// models/user.js
profile: belongsTo('profile', { async: true })

The reason is that model.profile will return a promise rather than a value. To solve that, you can use the afterModel hook as you suggested, but all you need is

afterModel(model, transition) {
  return model.get('profile');
},

That will issue the async call and pause the transition until it is completed, at which point the profile may be accessed as model.profile as usual. If for some reason you really want to access the profile as a controller property to avoid having to prefix it with model., just define an alias in your controller:

profile: Ember.computed.alias('model.profile')  

If there is more than one such property, then the following should do the job:

return Ember.RSVP.Promise.hash(this.getProperties('profile', ...));

You could also implement this right in the model hook, although it's a bit less readable:

model() {
  return this.store.findRecord('user', 1) .
    then(user => user.get('profile') . 
      then(() => user)
    );
}

What this says is, find the user, and then when found get his profile (which will cause the async request to fire), then when that is found return the user from the promise, so it is correctly set into model.

Upvotes: 5

Gennady Dogaev
Gennady Dogaev

Reputation: 5991

You don't need any of those code, because controller has access to model via this.model. In any controller's method you can just call this.get('model.profile'). In template you may use {{model.profile}}.

Upvotes: 1

Related Questions