EmberJS gotcha: Nested routes

As we know, one of the guiding principles of Ember is state encapsulation in the Ember route. In plain English, that means that the URL should tell the application everything it needs to know about the state of a page.

  • Yes, that means modals (query param, usually)
  • Yes, that means resources (path param, usually)
  • Yes, you see where this is going

Unfortunately, even with all the tooling (serious props guys), nested routes can be difficult for beginners to get right.

GitHub example repo: https://github.com/rmharrison/example-ember-nested-routes

Gotcha 1: Not using the Ember CLI

`ember g route <route_name>` is your friend.

  • Use it.
  • Always.
  • I’m serious
>>> ember g route bacon
I added the `<h1> bacon </h1>`

I’ve seen even senior developers spend longer than they’d care to admit debugging (hours!?) because they missed a level of nesting in either app/router.js or their directory structure. I know this stuff sounds trivial, but you spot the problem here:

Misplaced bacon in directory

Gotcha 2: Not using the Ember CLI

The CLI also supports generating nested routes, akin to `mkdir -p`. Unfortunately, there doesn’t appear to be a recursive creation feature.

>>> ember g route bacon/lettuce/tomato/aioli

Will only create the last child. It will not create the intermediate HBS files.

app/
└── templates/
└── bacon/
└── lettuce/
└── tomato/
├── aioli/
└── aioli.hbs

Gotcha 3: `index.hbs` vs `<route_name>.hbs`

app/template/bacon.hbs and app/template/bacon/index.hbs are not the same.

app/                  |     | app/
└── templates/ | != | └── templates/
└── bacon/ | ne | ├── bacon/
└── index.hbs | | └── bacon.hbs

By default, the Ember CLI will create app/template/bacon.hbs.

app/template/bacon/index.hbs will only render on the index route: https://host/bacon.

app/template/bacon/index.hbs will not be called on nested route calls: `https://host/bacon/1`.

app/template/bacon.hbs will be rendered for both URIs.

| URL                  | bacon/index.hbs | bacon.hbs |
|----------------------|-----------------|-----------|
| https://host/bacon | Y | Y |
| https://host/bacon/1 | N | Y |

Gotcha 4: Misusing `{{outlet}}`

If you don’t use an `{{outlet}}` your children will not render on the page.

It also helps to use the appropriate helper (`{{outlet}}`, `{{render}}`, `{{yield}}`), but that’s another topic.

Like what you read? Give Ryan M Harrison a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.