I can't access my models in controller


#1
app/routes/results/index.js

import Ember from 'ember';

export default Ember.Route.extend({
  model () {
    return Ember.RSVP.hash({
      results: this.store.find("key"),
      users: this.store.find("user")
    })
  },
  setupController (controller, models) {
    controller.setProperties(models)
  }
});

app/controllers/results/index.js

import Ember from 'ember';

export default Ember.ArrayController.extend({
  init () {
    let results = this.get("results");
    let users = this.get("users");

    // results is returning undefined
    // users is also undefined
   }
});

What I’m I doing wrong to access results and users in controller? I can access both models in the route.


#2

What version of Ember are you using? I believe ArrayController is deprecated. You might need an addon for that if you are using Ember 2.x

Otherwise I would try changing

export default Ember.ArrayController.extend({

into

export default Ember.Controller.extend({


#3

version: 2.2.0-beta.5


#4

I also tried

export default Ember.Controller.extend({
  init () {
     console.log("I'm getting here .....", this.get("results"))
  } 
})

// I'm getting here undefined

#5

OK, I am not sure about that setup controller function I have never really used the setProperties method. I would try two other things

1.) Use the model property directly in your template and remove the setup controller hook in your route.

e.g.

{{model.results}} and {{model.users}}

could use an each loop in template

2.) Or perhaps try a different approach in the setupController method. Because your model hook is returning a promise hash. Something like this should work

    setupController (controller, models) {
      controller.set('results' , models['results']);
      controller.set('users' , models['users']);
    } 

#6

what happens in your controller init method you do this?

  init () {
    this._super();
    console.log("I'm getting here .....", this.get("model"));
  } 

#7

When overriding code which already uses init(), always do:

init () {
    this._super( arguments );
    // rest of your code
}

http://emberjs.com/api/classes/Ember.Object.html#method_init


#8

You always need to reference the model in the controller. It looks like you’re expecting it to be destructured (which it will not).

 let results = this.get('model.retults');
 let users = this.get('model.users');

But, I would not start using controllers with Ember 2.2 (and definitely not ArrayControllers). They will be deprecated soon and really don’t give you that much benefit. In your template, just iterate over model.users:

{{#each model.users as |user|}}
  {{user.name}}
{{/each}}

The only time I’ve had to resort to using a Controller is when there are actions that I need to support in the route’s template.


#9

Humm, that is interesting. So if I want to decorate (add computed property to the model/s etc …) I will still do it in the route? Actually that’s what I ended up doing when this.get(“results”) … didn’t work for me in the controller.


#10

So if I want to decorate (add computed property to the model/s etc …) I will still do it in the route?

Great question. I have no idea what the “happy path” is on this one. I’ve been adding computed properties to the model so that the decoration stays with the underlying data. Seems like there’s a bit of mixing of concerns going on but it seems to work so far.


#11

Yeah, I like computed properties within the models. That feels natural. But if I need properties that are composites of attributes shared across multiple models then perhaps that is something to be done in a component.

Also the didReceiveAttrs hook inside a component is a great place to marshall together all the important attributes and implement logic where you need to synthesize things.


#12

Thanks for the comments!


#13

@samtes

andrew1 is correct but it’s also good to know what you did wrong. Your assumption: I “need” top setup my controller. Like andrew1 implied you don’t need to. The model property gets set automatically. There are however legitimate usecases to use setupController.

In your example you’re trying to access the results and users properties in the init method of the controller. The properties haven’t been set at that time.

The controller is first initialized for the route (init gets called). After which the route calls the setupController method.

Be aware that controller instances get cached. So re-entering/re-activating the route won’t cause init to be called (the previous instance of the controller will be reused). If you need to setup stuff in your controller after results and users get set you can observe these properties in your controller or set it up in setupController in the route (may be call controller.setup() from setupController?). You may also wan’t to take a look at the routes resetController method (http://emberjs.com/api/classes/Ember.Route.html#method_resetController).

Finally:

Indeed stay away from the ArrayController, it will save you the hassle from refactoring your code after it gets removed. You will most probably still need controllers until we get routeable components.


#14

Thanks for the elaborate explanation!