Setting active class to link. FlowRouter and zimme:active-route

My url looks like http://localhost:3000/homework.

And my route:

FlowRouter.route('/:notebookName', {
  action: function(params) {
    BlazeLayout.render("layout", { sidebar: 'homeSidebar', content: 'noteList' });
  }
});

And here’s how I’m trying to set the active class to my link:

{{#each notebooks}}
  <li class="{{isActiveRoute '/' path=name}}"><a href="/{{name}}">{{name}}</a></li>
{{/each}}

However clicking around the links isn’t changing the CSS class. Any suggestions?

You cannot mix route and path so you need to use either isActivePath or name

Still no dice with - any ideas?:

<li class="{{isActivePath '/' path=name}}"><a href="/{{name}}">{{name}}</a></li>`

because you cannot use '/' and path at the same time, since both are path. So you could use

{{isActivePath path=name}}

but it may not work because of the missing leading slash in which case you should create a custom helper using the javascript version of the helpers

Template.registerHelper('isActiveDynamicRootPath', function(pathName) {
  return ActiveRoute.path('/'+pathName) ? active : false;
});

and then use it like

{{isActiveDynamicRootPath path=name}}

This isn’t working either:

<li class="{{isActivePath path=name}}"><a href="/{{name}}">{{name}}</a></li>

I just want this url to highlight this link:

http://localhost:3000/Test
<li class="active"><a href="/Test">Test</a></li>

I’m not doing anything freaky here, I thought it would be easy to implement this sort of things so I’m positive I’m doing something wrong or my question wasn’t clear before. Thanks!

@arunoda do you have any suggestions?

Here’s how i’m doing in React… not exactly sure if #current is reactive? Also not sure how easy it is to grab the href in Blaze… should be do-able.

// template for header 'item'

var HeaderNavItem = React.createClass({
  isActive() {
    return FlowRouter.current().path === this.props.href;
  },

  render() {
    return (
      <li className={this.isActive() && 'active'}>
        <a href={this.props.href}>
          {this.props.name}</a>
      </li>
    );
  }
});  

Then just plop in like this and when the route changes, the active tab will reactively update:

<Header>
   <HeaderNavItem href='/about' name='About' />
   <HeaderNavItem href='/' name='Home' />
</Header>
1 Like

Ok here’s a solution based on my previous but it actually uses Blaze. I’ll post all of the files so you can run it as well. You don’t even need the active-route package :smile:

Since there is not getPath from the API, I had to use FlowRouter.getRouteName to trigger a re-render as FlowRouter.current() is not reactive.

@dgreensp @sashko Blaze can still rival React when you think modular ! :thumbsup:

Foo.html

<body>
  <h1>Welcome to Meteor!</h1>

  {{#Header}}
    {{> NavItem href='/'  name='Home'}}
    {{> NavItem href='/about'  name='About'}}
  {{/Header}}

</body>

<template name='NavItem'>
  <li class='{{activeClass}}'>
    <a href="{{this.href}}">{{this.name}}</a>
  </li>
</template>

<template name='Header'>
  <div class="header">
    {{> UI.contentBlock}}
  </div>
</template> 

Foo.js

FlowRouter.route('/about', {
  action: function(params, queryParams) {
    console.log('/about', params, queryParams);
  }
});

FlowRouter.route('/', {
  action: function(params, queryParams) {
    console.log('/home', params, queryParams);
  }
});


if (Meteor.isClient) {

  Template.NavItem.helpers({
    activeClass: function () {
      // make this re-render on change, even if we don't use var
      var routeName = FlowRouter.getRouteName();

      if (FlowRouter.current().path === this.href) {
            return 'active';
          }
        }
  });

}

Foo.css

.active a {
  color: red;
}

Hm, I thought you were trying to evaluate a path.

But for a top level route, you can do {{isActiveRoute name=name}}

To be frank, I find zimme active-route package lacking support for dynamically created nested routes; ie, you cannot (or I don’t know how) catch a /products/:_id/view route structure when you want to catch a “specific” product ID. But then, you can perhaps hack away using its regex property. But then you need some way to build the regex dynamically and for that, you need to be able to write javascript expressions within the handlebar helpers, and I guess that’s not supported.

For those, I guess the best bet is to use official FlowRouter API’s just like @SkinnyGeek1010 explained.

I definitely agree, most examples are not the best and make use of session.

I never use the session object, i mostly only keep states internally in the template using my frozeman:template-var and i make the templates in a way, that i pass the data in. This way i get nice reusable components and they save me a lot of refactor work, as i only have to go to one place :wink:

1 Like

I think this would cover a specific id.

{{isActivePath specificPath}}
Template.<name>.helpers({
  specificPath: function() {
    return '/products/' + FlowRouter.getParam('_id') + '/view';
  }
});

but for this, it might be cleaner to name the route which handles showing a specific product to like ‘showProduct’ and then use {{isActiveRoute 'showProduct'}} with this it would work for all _id’s.

I’ve actually thought about adding params attribute or something to support matching against route with specific parameters but as you can match against path I’ve thought that might have been enough.

This should work for your case, unless I’ve missed something.

{{#each notebooks}}
  <li class="{{isActivePath notebookPath}}"><a href="{{notebookPath}}">{{name}}</a></li>
{{/each}}
Template.<name>.helpers{{
  notebookPath: function() {
    return '/' + this.name;
  }
});
1 Like

do you have an example for react?