Create a gist now

Instantly share code, notes, and snippets.

@wycats /router-2.1.md Secret
Last active Dec 10, 2015

What would you like to do?

Router v2.1 TL;DR

Naming for Nested Routes

Nested routes will now create a namespace for their child routes to live under:

App.Router.map(function(match) {
  match("/blogs").to("blogs", function(match) {
    match("/favorites").to("favorites");
    match("/:blog_id").to("blog", function(match) {
      match("/info").to("info");
      match("/posts").to("posts");
    })
  })
});

The blogs route maps to:

  • blogs.handlebars
  • App.BlogsRoute
  • App.BlogsController

The blogs.favorites route, as a child of the blogs nesting, maps to:

  • blogs/favorites.handlebars
  • App.Blogs.FavoritesRoute
  • App.Blogs.FavoritesController

The blog route, starting a new group, creates a new namespace at the top level:

  • blog.handlebars
  • App.BlogRoute
  • App.BlogController

The blog.info route, as a child of the blog nesting, maps to:

  • blog/info.handlebars
  • App.Blog.InfoRoute
  • App.Blog.InfoController

Similarly, the blog.posts route, as a child of the blog nesting, maps to:

  • blog/posts.handlebars
  • App.Blog.PostsRoute
  • App.Blog.PostsController

Down the hierarchy, there will always only be a single level of nesting. Routes that begin a nesting create namespaces, and standalone routes inside of the nesting use the namespace.

Note that you do not need to create the namespace directly; Ember will create it for you because of the nested route definition.

Index Routes

All nested routes get a default index sub-route:

App.Router.map(function(match) {
  match("/posts").to("posts", function(match) {
    match("/:post_id").to("post");
  });
});

The above description creates a posts.index route automatically. If a user navigates to /posts, the optional posts/index template will be rendered by default.

A link to posts will work, and automatically generate a transition to posts.index.

This makes refactoring into nested routes pretty nice. Let's say you start here:

App.Router.map(function(match) {
  match("/posts").to("posts");
});
<!-- index.handlebars -->
<h1>You are at <code>/</code></h1>

{{#linkTo "posts"}}Go to the posts index{{/linkTo}}

<!-- posts.handlebars -->
<ul>
{{#each post in controller}}
<li>{{post.title}}</li>
{{/each}}
</ul>

Now, let's say you want to create a nested comments inside of posts:

App.Router.map(function(match) {
  match("/posts").to("posts", function(match) {
    match("/comments").to("comments");
  });
});
<!-- posts.handlebars -->
<ul>
{{#each post in controller}}
<li>{{post.title}}</li>
{{/each}}
</ul>

{{outlet}}

Links to posts will continue to work. Going to /posts will render the posts template, and leave its outlet empty.

You could also explicitly create a posts/index template or a Posts.IndexRoute if you wanted to have specific behavior for the root of /posts.

It's analogous to the index.html page if you go to a directory in a static web server.

No More App.Router =

You should never define App.Router = anymore. Ember creates App.Router for you when you create an Application.

If you want to configure the router, use reopen:

Ember.Router.reopen({
  location: 'history'
});

This is awesome! Thanks.

pdokas commented Jan 9, 2013

This helps clarify a lot of the questions about how to set up the default route when using nesting and how to configure the router. Thanks for sharing this info!

Wow didn't expect namespaces so quick. Great work guys!

Two questions:

  1. What is the problem that this is addressing?

  2. Would you have a conflict if you have something like this:

App.Router.map(function(match) {
  match("/blogs").to("blogs", function(match) {
    match("/:blog_id").to("blog", function(match) {
      match("/posts").to("posts");
    })
  }),
  match("/people").to("people", function(match) {
    match("/:blog_id").to("blog", function(match) {
      match("/posts").to("posts");
    })
  })
});

Two things that want the App.Blog namespace?

I'm also curious about the answer to lukemelia's second question. In our app we will have separate interfaces for admins and regular users, so there will be for example an adminRole.items.index route as well as a userRole.items.index route, which under this scheme would both fall under the App.Items namespace.

Although perhaps a better solution in this case is to have two separate Ember apps sharing models (?), I can still think of reasonable cases where there could be conflicting namespaces.

Easy-ish solution: allow the level of nesting to be specified as a parameter, rather than be hardcoded to 2?

@lukemelia Not sure what use case was for other's but in our app we have the following url structure:

/tags/:tag_id
   /activity
   /followers
   /contributors
/profiles/:profile_id
   /activity
   /followers
   /contributors

That worked great with old router but with new one we got naming conflicts, had to invent crazy naming conventions to make this work. Seems like router v2.1 will help us remove a lot of that.

Since this requires to namespace the models, such as App.Models.User, should we use Ember.Namespace for that?

drogus commented Jan 10, 2013

What's the reason for using Ember.Router.reopen?

pdokas commented Jan 10, 2013

@drogus As I understand it, the purpose for that is due to what @wycats wrote “Ember creates App.Router for you when you create an Application.”

Since Ember instantiates the Router singleton now, if you wish to customize it – e.g. change its URL mechanism from hashes to the history API – you need to reopen the class to pass your configuration options.

drogus commented Jan 10, 2013

@pdokas I probably asked the wrong question :) What I wanted to know was actually: why even change it to create Router automatically? Reopening classes is weird practice for me when it comes to setting application specific settings.

This looks great, thanks guys!

Can we get a gist for a Router v2.2 w route() & resource()? emberjs/ember.js@e4af09e

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment