Emberjs Controller initialisation

ember.js

Solution

I want to have an application template that uses the 'view' helper to include some other views.

The `{{view}}` helper is appropriate if all you want is a simple Ember.View with no controller. For example something like Ember.InputField. For an application's header and sidebar you'll typically want a view backed by a controller. In that case use the `{{render}}` helper instead. Have a look at this blog post for more details.

I also want to have some 'global' models that contain information about the environment (e.g. the logged in users account information etc.) that I want to be able to use in different views.

Makes sense. The right place to store that information is in a controller. That might be a property of `ApplicationController` or in a separate controller like `currentUserController`. Since a view should only access properties of it's own controller, you can use use controller's `needs` array to make it accessible. See managing dependencies between controllers

Is the controllerFor() creating a new instance a bug?

No, it is not a bug.

If not, why does it behave like this or what am I doing wrong?

Issue is that you are trying to manually create instances of headerController. In general if you are calling create() on a controller then something is wrong. Ember expects to manage controller instances itself, and will register them on the container so they can be found later. Since your instance was not registered, ember created a new one when you called controllerFor().

Is the way I worked around in my second fiddle a proper way to do it, or is there a better way?

Definitely not the proper way. In this fiddle you are using a global variable to accomplish what ember should be doing for you automatically. That means there is a lot of code that is not necessary, and also there is a lot of coupling between objects which makes things hard to test. If you go with the `{{render}}` approach it would look something like this:

<script type="text/x-handlebars" id="application">
    {{render header}}
    {{render sidebar}}
    {{outlet}}
</script>
<script type="text/x-handlebars" id="header">HEADER {{content}}<hr/></script>
<script type="text/x-handlebars" id="sidebar">SIDEBAR {{content}}<hr/></script>


App = Ember.Application.create({});
App.HeaderController = Ember.ObjectController.extend();
App.SidebarController = Ember.ObjectController.extend();
App.IndexRoute = Ember.Route.extend({
    setupController: function() {
      this.controllerFor('header').set('content', 'hi');
      this.controllerFor('sidebar').set('content', 'bye');
    }
});

Using `{{render}}` we don't need to define HeaderView or SidebarView since ember will generate them automatically. Each will be bound to a singleton instance of their controller, and those controllers can be accessed from your routes via `controllerFor`.

JSFiddle here: http://jsfiddle.net/NQKvy/1/

Problem

I'm playing with emberjs for a few days now and thought I understand the basics. Now I'm trying to build a real world application and already got stuck with a strange problem. I want to have an application template that uses the 'view' helper to include some other views. I also want to have some 'global' models that contain information about the environment (e.g. the logged in users account information etc.) that I want to be able to use in different views. I tried this: http://jsfiddle.net/UzgMd/7/ ``` <script type="text/x-handlebars" data-template-name="header"> <div>Header {{fullName}}</div> </script> <script type="text/x-handlebars" data-template-name="sidebar"> <div>Sidebar</div> </script> <script type="text/x-handlebars" data-template-name="application"> <div>{{view App.HeaderView}}</div> <div>{{view App.SidebarView}}</div> </script> <script type="text/javascript" src="http://code.jquery.com/jquery-1.9.1.min.js"></script> <script type="text/javascript" src="https://raw.github.com/wycats/handlebars.js/1.0.0-rc.3/dist/handlebars.js"></script> <script type="text/javascript" src="https://raw.github.com/emberjs/ember.js/release-builds/ember-1.0.0-rc.2.js"></script> <script type="text/javascript" src="https://raw.github.com/MilkyWayJoe/cdnjs/master/ajax/libs/ember-data.js/0.12.00-latest20130328/ember-data-latest.js"></script> ``` with the following JS: ``` App = Ember.Application.create(); App.Store = DS.Store.extend({ revision: 12, adapter: 'DS.FixtureAdapter' }); App.AccountInfo = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), fullName: function() { return this.get('firstName') + ' ' + this.get('lastName'); }.property('firstName', 'lastName') }); App.AccountInfo.FIXTURES = [{ id: 1, firstName: "John", lastName: "Doe" }]; //App.headerController = Ember.ObjectController.extend({}).create(); // works App.HeaderController = Ember.ObjectController.extend({}); // doesnt work App.HeaderView = Ember.View.extend({ templateName: 'header', //controller: App.headerController // works controller: App.HeaderController.create() // doesnt work }); App.SidebarView = Ember.View.extend({ templateName: 'sidebar' }); App.ApplicationController = Ember.Controller.extend({}); App.ApplicationRoute = Ember.Route.extend({ model: function() { return App.AccountInfo.find(1); }, setupController: function(controller, model) { this._super(controller, model); //App.headerController.set('model', model); // works this.controllerFor('header').set('content', model); // doesnt work } }); ``` but It doesn't work because the controllerFor()-method in line 47 returns a new instance of the HeaderController instead of the instance already created in line 30. If I call controllerFor() again, no new instance is created but the instance created by the call in line 47 is returned - what I find a bit confusing. However, if I do it like this: http://jsfiddle.net/UzgMd/8/ ``` App = Ember.Application.create(); App.Store = DS.Store.extend({ revision: 12, adapter: 'DS.FixtureAdapter' }); App.AccountInfo = DS.Model.extend({ firstName: DS.attr('string'), lastName: DS.attr('string'), fullName: function() { return this.get('firstName') + ' ' + this.get('lastName'); }.property('firstName', 'lastName') }); App.AccountInfo.FIXTURES = [{ id: 1, firstName: "John", lastName: "Doe" }]; App.headerController = Ember.ObjectController.extend({}).create(); // works //App.HeaderController = Ember.ObjectController.extend({}); // doesnt work App.HeaderView = Ember.View.extend({ templateName: 'header', controller: App.headerController // works //controller: App.HeaderController.create() // doesnt work }); App.SidebarView = Ember.View.extend({ templateName: 'sidebar' }); App.ApplicationController = Ember.Controller.extend({}); App.ApplicationRoute = Ember.Route.extend({ model: function() { return App.AccountInfo.find(1); }, setupController: function(controller, model) { this._super(controller, model); App.headerController.set('model', model); // works //this.controllerFor('header').set('content', model); // doesnt work } }); ``` using a singleton controller instance in that I inject the model, everything works fine. Now my questions: - Is the controllerFor() creating a new instance a bug? If not, why does it behave like this or what am I doing wrong? - Is the way I worked around in my second fiddle a proper way to do it, or is there a better way?

Original source