Organize Templates by Folders

Is there a way to organize the templates into folders? I want something similar to this:

templates/legal/terms-of-service.hbs templates/legal/privacy-policy.hbs templates/main/index.hbs

I tried putting the templates into folders and adding slashes to the name:

Router.map(function () {
  this.route('legal/terms-of-service', { path: '/legal/terms-of-service' });
  ...
});

To no success as when accessing the page i get a white screen.

Good question, the answer is yes and also no. Yes, you can organize them in folders, but not arbitrarily. In short they must match your route hierarchy. I think you can probably do what you want with a few adjustments but it depends on how you want things to be rendered.

Let’s look at the router:

Router.map(function () {
  this.route('legal/terms-of-service', { path: '/legal/terms-of-service' });
  ...          ^ this is route name                ^ this is route path
});

the route javascript file, and route template hbs file MUST match the “route name”. Route names should basically just be kebab case strings with no slashes. There are two ways to build your router here:

  1. flat router with customized paths, UI is not nested, but the file system cannot be either
  2. nested routes, UI is nested, file system is nested into directories too

I assume #2 is probably what you want but let’s look at them both.

1. Flat router

The router might look something like this:

Router.map(function () {
  this.route('legal-terms-of-service', { path: '/legal/terms-of-service' });
  this.route('legal-privacy-policy', { path: '/legal/privacy-policy' });
  ...
});

Which results in the following (named) routes:

legal-terms-of-service
legal-privacy-policy

The route/template files would be located as follows:

/app/routes/legal-terms-of-service.js
/app/routes/legal-privacy-policy.js
/app/templates/legal-terms-of-service.hbs
/app/templates/legal-privacy-policy.hbs

To create a link to those routes it would look like:

<LinkTo @route="legal-terms-of-service" ... />
<LinkTo @route="legal-privacy-policy" ... />

which would generate links with the following hrefs:

/legal/terms-of-service
/legal/privacy-policy

2. Nested routes

Router.map(function () {
  this.route('legal', function() {
    this.route('terms-of-service', { path: '/terms-of-service' });
    this.route('privacy-policy', { path: '/privacy-policy' });
    ...
  });
  ...
});

The routes/templates should look like:

/app/routes/legal.js                        // implicit
/app/routes/legal/index.js                  // implicit
/app/routes/legal/terms-of-service.js
/app/routes/legal/privacy-policy.js
/app/templates/legal.hbs                    //implicit
/app/templates/legal/index.hbs              // implicit
/app/templates/legal/terms-of-service.hbs
/app/templates/legal/privacy-policy.hbs

Which results in the following (named) routes, note the “.” separator at the parent/child boundary:

legal.index
legal.terms-of-service
legal.privacy-policy

To create a link to those routes it would look like:

<LinkTo @route="legal.terms-of-service" ... />
<LinkTo @route="legal.privacy-policy" ... />

which would generate links with the following hrefs:

/legal/terms-of-service
/legal/privacy-policy

I’m guessing this second version is what you’re looking for

Notes

Note that in the second (nested) option you end up with more routes. Ember implicitly creates an index route anytime there are child routes. This means that if someone visited /legal it wouldn’t throw an error, which is good. But by default the index route isn’t going to show anything. So there are two common ways to handle that:

  1. Just redirect to the default “legal” child route in the legal/index.js route file
  2. Set the path for one of the child routes to be '/' which makes it the new index route even if it’s not named index

Anothing thing to note is that with child routes the UI is nested. So in the above case the legal.hbs template is implicitly created for you with just an outlet. But if you wanted something to render across all your legal routes (like a special navbar or something) you could put it in that legal.hbs template above or below the outlet and it will render the child templates in the outlet. This is the same as the ember application route, just scoped to a smaller subset of routes.

3 Likes