by

Implicit index routes in Ember.js

TLDR: Ember.js implicitly creates an index child route for you when you nest under a route

This appears to be not so well known on the Ember community, and I don’t think it’s documented anywhere. I should have a go at clarifying this on the official docs (through a pull request on the project), but for the moment I’ll dump it here.

This is how it works. Say you declare a route in router.js:

1this.route('lines');

This declaration will get you a route, called lines. Nothing new here. Now let’s declare the same route, but with nesting:

1this.route('lines', function(){});

This is subtly different. We added nesting but left it empty, so there’s no reason to think that the result would be any different. However, there is indeed a difference. This will get you not one but two routes: lines and lines.index. Specifically, it’s the same as declaring the following:

1this.route('lines', function(){
2  this.route('index', { path: '' });
3});

This actually makes a lot of sense. If we think as lines as a “trunk” route and lines.index as a “leaf”, it turns out that trunk routes cannot be “landed”. These routes have an outlet that needs to be filled out. If we try to land on a trunk route, for example using transitionTo, Ember will redirect us to the index leaf route under them, and the outlet will get its content. In other words, these two transitions are equivalent, assuming that lines is a route with nesting:

1this.transitionTo('lines');
2this.transitionTo('lines.index');

These implicit index routes are implemented with an empty route module and an empty template. We don’t notice any of this, but we can verify it by using the Ember Inspector, where we can see these routes, along with loading and error subroutes:

Implicit routes showing up on the Ember Inspector

Implicit routes showing up on the Ember Inspector

This can go several levels deep. If we explicitly declare an index route with nesting, Ember will declare yet another index under it:

1this.route('lines', function(){
2  this.route('index', { path: '' }, function() {
3  });
4});

If we try to transition to lines, Ember will take us to lines.index and then in turn to lines.index.index. This can go on for as long as necessary, until a leaf route is found where we can land safely.