How do you render different layouts?


#1

I have a basic scenario where i have to show different layout to guests vs authenticated users.
I tried to render other template than the application one by using below code in my route file:

renderTemplate(){
    this.render('login', {   // the template to render
        into: 'guest',         // the template to render into
        // outlet: 'login',     // the name of the outlet in that template
        // controller: 'login'  // the controller to use for the template
    });
}

but when i do so i get Uncaught Error: Assertion Failed: You attempted to render into 'guest' but it was not found even though the files are all there which seems to be a bug(?).

The only way i managed to get this working is to output only {{outlet}} into the application.hbs template then in all my other templates do something like:

{{title "Login"}}
{{partial "partial/guest-header"}}
...markup...
{{partial "partial/guest-footer"}}

which get rendered in app.hbs {{outlet}}, but this seems very tedious to maintain.

I also tried to edit application.js as in:

renderTemplate(){
        if (this.router.currentRouteName == "login") {
          this.render('guest');
        } else {
          this.render('application');
        }
    }

But seems that this.router.currentRouteName is undefined at init and in order to make it work i have to place it into a Ember.run.later call, which again, seems very odd to do.

So, that being said, what is the proper way to use various layouts? I mean, why is this so hard to achieve, is like i am fighting the framework (most likely i am) ?


#2

Really, nobody knows how to render different layouts? Weird…


#3

Many people know how to do this, they just didn’t see your post and reply to it.

I cover it in my embercamp London talk: http://alexspeller.com/embercamp-london-talk-routing/


#4

@alexspeller - Thank you, finally something that makes sense. Great talk too :wink:


#5

Can we have a textual response?


#6

i met the same problem. :disappointed_relieved:


#7

So, what’s going on really? i am confused.


#8

You need to create two parent routes like this:

  this.route('logged-in', {path: '/'}, function(){
    this.route('inventory', {resetNamespace: true}, function() {
      this.route('view', {path: ":id"});
    });
  });
  
  this.route('login');

The logged-in route and template contains all of your toolbars, navbars etc when you’re logged in as well as an unnamed outlet, like this:

  {{bread-crumbs tagName="ol" outputStyle="bootstrap" linkable=true}}

  <div class="page-wrapper">
    <div class="container-fluid">
      <div class="row">
        <div class="col-lg-12">
          {{outlet}}
        </div>
      </div> <!-- .row -->
    </div> <!-- .container-fluid -->
  </div> <!-- .page-wrapper -->
</div>  <!-- .wrapper -->

The log in route just has your login form.

Then you need to make your application template like this:

{{outlet "logged-in"}}
  
{{outlet "login"}}

Then you need to make your login route have a renderTemplate like this:

  renderTemplate: function(){
    this.render("login", {
      outlet: "login"
    });
  }

Whilst your logged-in route has a render template like this:

  renderTemplate: function(){
    this.render("logged-in", {
      outlet: "logged-in"
    });
  }

Transitioning between login and any of the child routes under “logged-in” will hide the UI elements.

The resetNamespace stuff and setting the logged-in path to “/” prevents the URL from showing “logged-in”.