Menu
Now that our routes are working we can create a menu:
client/views/layout.html
<template name="layout">
<h1>Foosboom</h1>
<ul>
<li><a href="/">Games</a></li>
<li><a href="/teams">Teams</a></li>
</ul>
{{> loginButtons}}
{{> yield}}
</template>
However there is a problem with this menu: we can't tell which menu item has been selected.
To fix this we need to style our "active" menu item differently. But to do that we need to know which menu item is active so we can give it a different CSS class.
Don't reinvent the wheel
Since most apps require this functionality it's highly likely someone has created a package for this. I like to browse packages on Atmosphere, check compiled package lists, as well as looking over well maintained Meteor boilerplate projects (here's one, and another) just to make sure I'm not reinventing the wheel with certain functionality.
In saying this I should warn you that some packages can be poorly maintained - meaning that at some point in the future they might suddenly break after a Meteor update or something. To protect against this you just need to check that the Github project seems to be reasonably active. Are there many commits? Are issues being resolved? Is the package recommended by any blogs or boilerplate projects? The last thing you want is for your app to fail because a third-party package is causing a random bug.
meteor-iron-router-active
Anyway after some searching I found meteor-active-route, which seems perfect for our needs, and is recommended by a popular boilerplate Meteor app (making it trustworthy in my opinion).
Let's add it to our project:
meteor add zimme:active-route
client/views/layout.html
<template name="layout">
<h1>Foosboom</h1>
<style>
.active a {color: black;text-decoration: none;border: 1px solid black}
</style>
<ul>
<li class="{{isActiveRoute regex='games'}}">
<a href="/">Games</a>
</li>
<li class="{{isActiveRoute regex='teams'}}">
<a href="/teams">Teams</a>
</li>
</ul>
{{> loginButtons}}
{{> yield}}
</template>
It appears this is only half working - it works for teams
but not for games
. The reason for this is that Iron Router allocates a "name" to each route. When we created our teams
route with Router.route('/teams', 'teams')
it was able to guess the name to be "teams" (/teams
=> "teams").
But with our games
route (Router.route('/', 'games')
, Iron Router only had /
to obtain a name from (/
=> ?), and hence didn't name it anything. We can check the name of the current route (docs) by opening the browser console and typing:
Router.current().route.getName()
Luckily, it's quite easy to specify a name for our route:
both/router.js
Router.configure({
layoutTemplate: 'layout'
});
Router.route('/', {name: 'games'});
Router.route('/teams', 'teams');
Here we have named our route games
, but not supplied a template. Luckily it still works because if Iron Router has a name for the route then it automatically searches for a template with the same name. So it saw the name was "games" and then searched for a template called "games". With this knowledge we can further simplify our teams
route:
both/router.js
Router.configure({
layoutTemplate: 'layout'
});
Router.route('/', {name: 'games'});
Router.route('/teams');
Feel free to style it better.