When defining routes in ember, there is one very important thing to keep in mind. We should only nest our routes when our UI is nested. Sometimes it is necessary to display a template inside another template and here we use nested routes.
Let’s now learn how to create nested routes. We can take a look at the notifications page in our Open Event Frontend for better understanding.
Here the part in red is common to all the sub-routes of notification, thus one method of achieving this could be copy-pasting the same code in all the sub-routes. Obviously this is not the correct method and it increases the code redundancy.
The correct method here is, using nested routes.
ember generate route notifications
ember generate route notifications/index
ember generate route notifications/all
Here notification is the parent route and index, all are it’s nested or sub-routes. It can be seen in router.js in the given form
this.route(‘notifications’, function() { this.route(‘all’); }); |
But wait we see no route for notifications/index…. did something go wrong ?
No. At every level of nesting, ember automatically creates a route for the path ‘/’ named index. So the above code snippet in router.js is equivalent to
this.route(‘notifications’, function() {
this.route(‘index’,{ path: ‘/’}); |
Now let’s have a look at our parent route ie /notifications. As stated above only the part in red has to be present here, So we have added semantic-ui’s header, buttons and used link-to helper to link them to respective route. An interesting thing to note here is that ‘Mark all read’ is not present in both its sub routes, so we need to check the route before displaying this button. We have checked the current route using session.currentRouteName and only when the current route is not notifications/all we display the button.
<h1 class=“ui header”>{{t ‘Notifications’}}</h1> <div class=”ui divider”></div> <div class=“row”> {{#link-to ‘notifications’}} <button class=“ui button”>{{t ‘Unread’}}</button> {{/link-to}} {{#link-to ‘notifications.all’}} <button class=“ui button”>{{t ‘All’}}</button> {{/link-to}} {{#if (not-includes session.currentRouteName ‘notifications.all’)}} <button class=“ui button right floated”>{{t ‘Mark all read’}}</button> {{/if}} </div> {{outlet}} |
We have added the {{outlet}} helper in our notifications.hbs where we want our nested templates to be displayed. For understanding we can imagine this as the whole code of notifications/all is being copied into this outlet helper i.e notifications/all.hbs is rendered into the {{outlet}} of notifications.hbs
Let’s now have a look at our sub-route i.e notifications/all.hbs. We now know that this will be rendered in the red part stated below
We have added Semantic-Ui’s segments class for every notification. A blue colour has been added to the segments if the notification is not read. We have used Semantic-Ui’s grid class to structure the content inside each notifications. We are getting date object from js and to convert it into human readable format we have used moment like {{moment-from-now notification.createdAt}}
{{#each model as |notification|}} <div class=“ui segment {{unless notification.isRead ‘blue’}}”> <div class=“ui grid”> <div class=“row”> <div class=“eight wide column”> <h4 class=“ui header”>{{notification.title}}</h4> <p>{{notification.description}}</p> </div> <div class=“eight wide column right aligned”> <i class=“checkmark box icon”></i> </div> </div> <div class=“row”> <div class=“ten wide column”> <button class=“ui blue button”>{{t ‘View Session’}}</button> </div> <div class=“six wide column right aligned”> <p>{{moment-from-now notification.createdAt}}</p> </div> </div> </div> </div> {{/each}} |
We have reused notifications/all.hbs for index route by explicitly defining templateName: ‘notifications/all’, in notifications/index.js.
Additional Resources