Question

I've been playing around with Meteor + Iron Router for a multi-page app I'm working on and I'm getting stuck on helper functions for named yields. Specifically, I've been trying to get the active class for my navbar tabs to update on each route change.

Below is the relevant code for my project:

router.js

Router.configure({
  layoutTemplate: 'mothership',
  yieldTemplates: {
  'header' : {to: 'header'},
  'footer': {to: 'footer'}
  },
});

Router.map(function () {
  // Home page
  this.route('home', {
    path: '/',
    template: 'home',
  });

  this.route('about', {
    path: '/about',
    template: 'about',
  });

  this.route('emails', {
    path: '/emails',
    template: 'emails',
  });

  this.route('people', {
    path: '/people',
    template: 'people',
  });
}); 

mothership.html

<template name="mothership">
  <a href="#content" class="sr-only">Skip to content</a>
  <div id="wrap">
    <!-- header -->
    <div>{{yield 'header'}}</div>
    <div id="content">{{yield}}</div>
  </div>

  <div id="push"></div>
  <div id="footer">
    {{yield 'footer'}}
  </div>
</template>

header.html

...bootstrap stuff...
<a class="navbar-brand" href="{{pathFor 'home'}}">Mailchacho</a>
<li class="{{activeRoute 'about'}}"><a href="{{pathFor 'about'}}">About</a></li>
<li class="{{activeRoute 'emails'}}"><a href="{{pathFor 'emails'}}">Sent Emails</a></li>
<li class="{{activeRoute 'people'}}"><a href="{{pathFor 'people'}}">People</a></li>
...bootstrap stuff...

header.js

Handlebars.registerHelper('activeRoute', function(name) {
  var active = location.pathname === Router.path(name);
  return (active) ? 'active' : '';
});

// I know I can use Template.headers.helpers... to do this as well, I just found the registerHelper to be cleaner.

When I load a page from scratch, the proper active class is assigned, but when a route is changed on-page, the active class doesn't update. Using breakpoints, I can see the 'activeRoute' function isn't called on a change.

What's interesting is if I add a data dictionary to router.js, it does update. My guess is having the data dictionary indicates that something has changed between routes, forcing a refresh. What I'd like to do is have this refresh occur without needing to pass a data dictionary.

Since Iron Router is still fairly new, I haven't been able to able to find much online. The closest I've found is this issue on github (https://github.com/EventedMind/iron-router/issues/103), but the last comment was never resolved, which seems to be similar to mine.

With the above in mind, is there any way I can signal for a helper function to be rerun on a route change without passing a dummy data dictionary? I was thinking that something like Deps.autorun might be needed, but that doesn't feel right. I'm still pretty new to Meteor & Iron Router so any help here would be appreciated. Thanks!

Was it helpful?

Solution

Yours is a common problem so Mike Fitzgerald has built a package just for this purpose:

https://atmosphere.meteor.com/package/iron-router-active

The given example is like:

<nav>
    <ul>
        <li class="{{ isActive 'dashboard' }}">...</li>
        <li class="{{ isActive 'dashboard|root' }}">...</li>
        <li class="{{ isActive 'users' 'on' }}">...</li>
        <li class="{{ isActivePath 'products' }}">...</li>
    </ul>
</nav>

andd works through handlebars helpers which are called isActive, isActivePath, isNotActive and isNotActivePath.

OTHER TIPS

I use meteor add zimme:active-route now. It works with iron:router, kadira:flow-router and meteorhacks:flow-router.

Just two examples: Output active class:

<li class="{{isActiveRoute 'home'}}">...</li>

Custom class:

<li class="{{isActiveRoute 'home' class='is-selected'}}">...</li>

https://atmospherejs.com/zimme/active-route

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top