Skip to content

Instantly share code, notes, and snippets.

@wycats
Last active December 10, 2015 20:48
Show Gist options
  • Star 28 You must be signed in to star a gist
  • Fork 3 You must be signed in to fork a gist
  • Save wycats/1b54b0eaf48eabbcff24 to your computer and use it in GitHub Desktop.
Save wycats/1b54b0eaf48eabbcff24 to your computer and use it in GitHub Desktop.

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'
});
@alan-andrade
Copy link

This is awesome! Thanks.

@pdokas
Copy link

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!

@darthdeus
Copy link

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

@lukemelia
Copy link

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?

@markprzepiora
Copy link

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?

@mikegrassotti
Copy link

@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.

@darthdeus
Copy link

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

@drogus
Copy link

drogus commented Jan 10, 2013

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

@pdokas
Copy link

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
Copy link

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.

@joefiorini
Copy link

This looks great, thanks guys!

@andrewmp1
Copy link

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

@mixonic
Copy link

mixonic commented Jan 21, 2013

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