0

I'm confused on how to manage global sections on the page that are not using a route, for example a notifications dropdown.

The notifications dropdown will always be visible and should update accordingly.

This is what I have tried.

Set the notifications on the ApplcationContoller

App.ApplicationRoute = Ember.Route.extend({
    setupController: function(controller) {
        controller.set('notifications', this.store.find('notification'));
    }
});

And use them in the ApplicationTemplate

<script type="text/x-handlebars">
   {{#each notifications}}
      Message: {{message}}
   {{/each}}
<script>

Although this works it doesn't seem right as I would like the notifications to at least have it's own controller.

So I couldn't figure out how to assign a controller to the notifications so I created a view for the notifications and tried assigning the controller that way, like this.

Created a view for the notifications

App.NotificationsView = Ember.View.extend({
    controller: App.NotificationsController.create(),
    templateName: 'notifications'
});

Created a notifications template

<script type="text/x-handlebars" data-template-name="notifications">
    Notifications
</script>

Created the NotificationsController

App.NotificationsController = Ember.Controller.extend({
    init: function() {
        this._super();
        this.set('content', this.store.find('notification'));
    }
});

And I get the following error.

Uncaught TypeError: Cannot call method 'find' of null 

Which is obviously saying that this.store is null

So overall, what is the best way to achieve this sort of functionality?

iConnor
  • 19,997
  • 14
  • 62
  • 97

1 Answers1

2

You can used named outlets and achieve the desired behavior:

Add a named outlet to the template where you want to have the notifications rendered:

<script type="text/x-handlebars">
   {{outlet notificationsOutlet}}

   {{outlet}}
<script>

Setup the controller in the corresponding route:

App.ApplicationRoute = Ember.Route.extend({
    setupController: function(controller, model) {
        this._super(controller, model);
        this.controllerFor('notifications').set('model', this.store.find('notification'));
    }
    ...
});

And render into the named outlett:

App.ApplicationRoute = Ember.Route.extend({
    ...
    renderTemplate: function(controller, model) {
        this._super(controller, model);
        this.render("notifications", {
          into: "application", // should be possible to leave this one out
          outlet: "notificationsOutlet",
          controller: this.controllerFor("notifications")
        });
    }
});

UPDATE: Or even shorter: Use the {{render}} helper!

Again setup the controller like above:

App.ApplicationRoute = Ember.Route.extend({
        setupController: function(controller, model) {
            this._super(controller, model);
            this.controllerFor('notifications').set('model', this.store.find('notification'));
        }
        ...
    });

More easy render rendering: The render helper allows you to render a controller and view given by name.

<script type="text/x-handlebars">
   {{render notifications}}

   {{outlet}}
<script>

You can find a more general description of this two techniques here.

Community
  • 1
  • 1
mavilein
  • 11,648
  • 4
  • 43
  • 48
  • Thanks, I was half way there, I had just figured out about `render` and managed to do that, the problem i faced then is i tried to set the `content` in the `NotificationsController` using `set` & `this.store.find` but it was returning a `promise` and never actually getting the data, although that the data is displayed in ember debugger, so i think your solution would fix that error using `controllerFor`, I'll try it and let you know, thanks.. – iConnor Nov 07 '13 at 19:39
  • And it does thanks, do you know why setting it with `controllerFor` works but not `init: function() { this._super(); this.set('content', this.store.find('notification'));}`? in the `NotificationsController` – iConnor Nov 07 '13 at 19:40
  • When you perform this logic in the `init` function, you are skipping the "magic" of ember, which injects the store into your controller. When you use `controllerFor` Ember makes sure that everything is setup correctly. – mavilein Nov 07 '13 at 19:42
  • Oh, and the `{{render something}}` is cool, I'll use that. Ember.js is really frustrating me at the moment, but i think that's a good thing, when a framework/library frustrates you in the beginning it turns out to be amazing when you get the hang of it. – iConnor Nov 07 '13 at 19:43
  • Ok, it just doesn't seem right to me if you set the data for a controller outside of a controller... Thanks a lot for the help :) – iConnor Nov 07 '13 at 19:44
  • You are nearly there. This is already an advanced topic in Ember and is not included in many tutorials and maybe frustrating at the beginning :-) – mavilein Nov 07 '13 at 19:44
  • In Ember terms the right place to set the controller content is the route! Think of the model hook. The result of this hook is also just set in the same way on your controller. Exactly the same mechanism. This makes it possible to change the content of controllers because in another place in your app an event was triggered. – mavilein Nov 07 '13 at 19:45