Search code examples
ember.jsroutesstates

Ember routes + outlets


After diving into Backbone + Marionette for quite a long time, I've been training with Ember for a week or so. I've been able to play with it and build a blog easily. As long as the app relies on routes it's fine. Now I would like to build an app which only has 2 routes, and relies more on states. I want to define the following nested HTML structure :

<div id="topbar"></div>
<div id="content"></div>
<div id="botbar"></div>

I would like the topbar and botbar to remain the same whatever the content is. Content could be "pos content"

<div id="pos">
    <div id="leftsidebar">...</div>
    <div id="cart">...</div>
    <div id="buttons">...</div>
    <div id="rightsidebar">...</div>
    <div id="header">...</div>
</div>

or "params content"

<div id="params">...</div>

So far i've managed to build the 1st level of nesting using the following code :

App = Em.Application.create({});

App.Router.map(function() {
    this.route('index', { path: '/' });
    this.route('params', { path: '/params' });
});

App.IndexRoute = Em.Route.extend({
    renderTemplate: function() {
        this.render();
        this.render('topbar', { outlet: 'topbar' });
        this.render('pos', { outlet: 'content' });
        this.render('botbar', { outlet: 'botbar' });
    }       
});     

App.ParamsRoute = Em.Route.extend({
    renderTemplate: function() {
        this.render();
        this.render('topbar', { outlet: 'topbar' });
        this.render('params', { outlet: 'content' });
        this.render('botbar', { outlet: 'botbar' });
    }
});

I see in chrome Ember extension that the routes are defined, and my controllers (TopbarController, BotbarController and PosController/ParamsController depending on the route) seems to be instanciated.

Now what I would like is going deeper, and have a controller per sub-outlet (leftsidebar, cart, etc.) but I have no idea how to build the second level of nesting.

The documentation doesn't seem to help me and google is not my friend on this :( Could you guys help me out ? Thank you.


Solution

  • outlets in ember are contextual to the currently active route.

    If you have the following application template

    <div id="topbar">
      {{ outlet 'topbar' }}
    </div>
    <div id="content">
      {{ outlet }}
    </div>
    <div id="botbar">
      {{ outlet 'botbar' }}
    </div>
    

    You could clean up your repeatitive code by moving it into the ApplicationRoute

    App.ApplicationRoute = Ember.Route.extend({
      renderTemplate: function(){
        this._super.apply(this, arguments);
        this.render('topbar',{outlet: 'topbar', into: 'application'})
        this.render('botbar',{outlet: 'botbar', into: 'application'})
    
      }
    })
    

    Now you can have the following index template

    <div id="index">
      <div id="left">
        {{ outlet "left" }}
      </div>
      <div id="content">
        {{ outlet }}
      </div>
      <div id="right">
        {{ outlet 'right' }}
      </div>
    </div>
    

    You need to clarify which context the outlet is located in by rendering "into" it.

    App.IndexRoute = Ember.Route.extend({
      renderTemplate: function(){
        this._super.apply(this, arguments);
        this.render('right',{outlet: 'right', into: 'index'})
        this.render('left',{outlet: 'left', into: 'index'})
    
      }
    })