Search code examples
ember.jsember-router

in ember v2 router why isn't controllerFor() giving a reference to this controller?


Here's the fiddle.

http://jsfiddle.net/inconduit/hf7XM/10/

Steps to reproduce the issue:

  • Click on 'Go to Posts'.
  • Click the 'controllerFor' text, it won't clear the list.
  • Click the global reference text, it will clear the list.

It seems that the controller reference returned by controllerFor() is not actually the PostsIndexController? Why is that?

I hacked it in the setupController() hook of the Route to set a global reference to that controller on App, and when I set the content on that reference to a new array in emptyList2(), the list correctly clears in the template.

Am I using controllerFor() wrong? Or misunderstanding what it's returning? Is it a scoping issue? Please help me out.

App.PostsIndexRoute = Ember.Route.extend({
  setupController : function(controller,model) {
    controller.set('content',['one','two','three']);
    App.postsIndexController = controller;
  }
});

// receives the {{action}} from the template
App.PostsController = Ember.Controller.extend({
  emptyList : function() {
    this.controllerFor('postsIndex').set('content',Ember.A());
  },
  emptyList2 : function() {
    App.postsIndexController.set('content',Ember.A());
  }  
});

Solution

  • tldr: replace controllerFor('postsIndex') with controllerFor('posts.index')


    The emptyList2 fx was working because you'd set the App.postsIndexController constant to be whatever controller instance got handed to setupController.

    I think more important than how to fix this is how to debug these kinda problems. Here's what I did:

    Opened the JS console while running that JS fiddle. After clicking the posts links but before trying to empty the list, I ran the following:

    Em.keys(App.__container__.cache.dict)
    ["application:main", "router:main", "route:application", "route:index", "controller:application", "template:application", "controller:index", "template:index", "route:posts", "route:posts.index", "controller:posts", "template:posts", "controller:posts.index", "template:posts.index"]
    

    Then after clicking the emptyList action, tried again:

    Em.keys(App.__container__.cache.dict)
    ["application:main", "router:main", "route:application", "route:index", "controller:application", "template:application", "controller:index", "template:index", "route:posts", "route:posts.index", "controller:posts", "template:posts", "controller:posts.index", "template:posts.index", "controller:postsIndex"]
    

    See how there are now 2 cached instances of App.PostsIndexController: controller:postsIndex and controller:posts.index

    Then I added a few console.logs to the jsFiddle to see what instances were being referenced. From there it was pretty easy to make the fix. Since Ember adds a toString() method to every object it is pretty easy to see what is going on. For example:

    controllerFor("postsIndex").toString()
    <App.PostsIndexController:ember218>
    

    Updated fiddle here: http://jsfiddle.net/mgrassotti/Aa2WX/2/