40

I have a list and I'd like to set one item as class="active" automatically. Given the following bootstrap code:

<ul class="nav">
<li {{bindAttr class="atIndex:active"}}>{{#linkTo "index"}}Index{{/linkTo}}</li>
<li {{bindAttr class="atAbout:active"}}>{{#linkTo "about"}}About{{/linkTo}}</li>
<li {{bindAttr class="atLogin:active"}}>{{#linkTo "login"}}Login{{/linkTo}}</li>
</ul>

atIndex, atAbout and atLogin reside in my ApplicationController.

To render as:

<ul class="nav">
<li class="active"><a...>Index{{/linkTo}}</li>
<li><a...>About<a></li>
<li><a...>Login<a></li>
</ul>

What's the best way to do this with Ember 1.0 pre4? I'd rather not add special code to every view or controller.

PS - atIndex: true works, but atIndex: function() {return true; }.property().volatile() does not. Which makes me think I'm doing something wrong.

Thank you!

shs
  • 887
  • 1
  • 9
  • 14

12 Answers12

75
{{#link-to "dashboard" tagName="li" href=false}}
  <a {{bind-attr href="view.href"}}>
    Dashboard
  </a>
{{/link-to}}
Seth McClaine
  • 9,142
  • 6
  • 38
  • 64
lesyk
  • 3,979
  • 3
  • 25
  • 39
14

By far the cleanest way to solve this is by taking advantage of the linkTo helper's built-in support for setting the active class when rendering links. AFAIK this is not yet documented other than in the source code:

implementation: https://github.com/emberjs/ember.js/blob/master/packages/ember-routing/lib/helpers/link_to.js#L46

example: https://github.com/emberjs/ember.js/blob/master/packages/ember/tests/helpers/link_to_test.js#L120

To take advantage of this feature just adjust your css to style based on having an active class on the link instead of the li element. If you really need to style the li you can create a custom view and helper that extends Ember.LinkView and uses an li but changing css will be far easier.

--- UPDATE ----

Since we all love twitter bootstrap just changing the css is perhaps not such a great option. In that case, the following will do the trick:

App.ApplicationView = Ember.View.extend({
  currentPathDidChange: function() {
    Ember.run.next( this, function() {
      this.$("ul.nav li:has(>a.active)").addClass('active');
      this.$("ul.nav li:not(:has(>a.active))").removeClass('active');
    });
  }.observes('controller.currentPath')
});

Working example using ember linkTo helper with bootstrap pills: http://jsbin.com/ekobod/5/edit (requires ember-1.0.0-pre.4)

Mike Grassotti
  • 19,040
  • 3
  • 59
  • 57
  • Unfortunately for this problem I'm using the popular javascript-bootstrap controls in my project. (Fortunately, though, because they're really great. :-) It would be neat if the linkTo could somehow push a value into the controller automatically that in turn would bind to the
  • 's active class.
  • – shs Jan 19 '13 at 17:49
  • The closest I've found is this solution: http://stackoverflow.com/questions/14328295/how-do-i-bind-to-the-active-class-of-a-link-using-the-new-ember-router – shs Jan 20 '13 at 00:18
  • 1
    There is a new pull-request with solution for wrapping linkTo tag in an li, might want to have a look and comment https://github.com/emberjs/ember.js/pull/1849 – Mike Grassotti Jan 23 '13 at 03:24
  • Neat stuff there. I filed [this one](https://github.com/emberjs/ember.js/issues/1822) but it wasn't as popular. Thanks! – shs Jan 23 '13 at 14:57
  • 2
    This function `currentPathDidChange` is only run when the path-depth is changing. Not when the same level is changing: from `/pages/1` to `/pages/2` – Willem de Wit Feb 15 '13 at 15:54
  • Thanks Mike, your solution works Ok with nested navs with which I hade problems using Yehuda's solution from the link above – Qrilka Mar 14 '13 at 07:41
  • `this.$("ul.nav li:has(>a.active)").addClass('active'); this.$("ul.nav li:not(:has(>a.active))").removeClass('active');` is changing the class of the tag. How can I get it to change the class of the
  • tag to work with bootstrap?
  • – Dan Baker May 10 '13 at 20:22