Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Assigning 'active' class to selected list item in EmberJS

Tags:

ember.js

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!

like image 702
shs Avatar asked Jan 19 '13 07:01

shs


6 Answers

{{#link-to "dashboard" tagName="li" href=false}}
  <a {{bind-attr href="view.href"}}>
    Dashboard
  </a>
{{/link-to}}
like image 121
lesyk Avatar answered Nov 08 '22 09:11

lesyk


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)

like image 36
Mike Grassotti Avatar answered Nov 08 '22 10:11

Mike Grassotti


the active route's path is updated automatically in the ApplicationController via currentPath so I did something like that in my App... In ApplicationController added properties like so:

isProductsActive: function(){
  if ( this.get('currentPath') === 'products' ) return 'active';
  else return '';
}.property('currentPath')

and in my ApplicationView template:

<li {{bindAttr class="isProductsActive"}}>
  {{#linkTo "products"}}Products{{/linkTo}}
</li>
like image 5
colymba Avatar answered Nov 08 '22 10:11

colymba


I made an ember-cli addon that handles this:

https://github.com/alexspeller/ember-cli-active-link-wrapper

like image 5
alexspeller Avatar answered Nov 08 '22 10:11

alexspeller


EDIT: Finally, the best way I've found to use the activate class of bootstrap li element using ember.js of the link.

{{#linkTo "dives" tagName="li"}}
   <a {{bindAttr href="view.href"}}>Dives</a>
{{/linkTo}}

--------------8<--------------

DEPRECATED:

I guess the previous answers were relevant before Ember.js introduced the activeClass attribute for linkTo helper. Now I would solve the problem like this :

<ul class="nav">
<li >{{#linkTo "index" activeClass="active"}}Index{{/linkTo}}</li>
<li >{{#linkTo "about" activeClass="active}}About{{/linkTo}}</li>
<li >{{#linkTo "login" activeClass="active}}Login{{/linkTo}}</li>
</ul>

Enber will automatically add the class when relevant.

like image 3
Cyril Avatar answered Nov 08 '22 10:11

Cyril


If I may suggest another solution that requires nothing but Handlebars:

<li {{bind-attr class="view.innerLink.active:active"}}>
    {{#link-to "path" viewName="innerLink"}}Click{{/link-to}}
</li>

This sets the LinkView object as a member of the parent view, which's active attribute you can then reference.

like image 2
Elte Hupkes Avatar answered Nov 08 '22 09:11

Elte Hupkes