emberjs - how to mark active menu item using router infrastructure

24,313

Solution 1

If you're using Ember >= 1.11, then https://stackoverflow.com/a/14501021/65542 below is the correct answer.


I would create a NavigationView, see http://jsfiddle.net/pangratz666/z8ssG/:

Handlebars:

<script type="text/x-handlebars" data-template-name="navigation">
    <ul class="nav nav-tabs">
        {{#view view.NavItemView item="home" }}
            <a {{action gotoHome}} >Home</a>
        {{/view}}
        {{#view view.NavItemView item="profiles" }}
            <a {{action gotoProfiles}} >Profiles</a>
        {{/view}}
        {{#view view.NavItemView item="messages" }}
            <a {{action gotoMessages}} >Messages</a>
        {{/view}}        
    </ul>
</script>

JavaScript:

App.NavigationView = Em.View.extend({
    templateName: 'navigation',
    selectedBinding: 'controller.selected',
    NavItemView: Ember.View.extend({
        tagName: 'li',
        classNameBindings: 'isActive:active'.w(),
        isActive: function() {
            return this.get('item') === this.get('parentView.selected');
        }.property('item', 'parentView.selected').cacheable()
    })
});

And inside your route's connectOutlets you have to set the current navigation item via router.set('navigationController.selected', 'home'); ...


Also take a look at the ember-bootstrap repository, which wraps this and more features of Bootstrap inside Ember.js

Solution 2

Ember 1.11+:

{{#link-to "dashboard" tagName="li"}}
  <a href="{{view.href}}">Dashboard</a>
{{/link-to}}

Ember < 1.11 (bind-attr required):

{{#link-to "dashboard" tagName="li"}}
  <a {{bind-attr href="view.href"}}>Dashboard</a>
{{/link-to}}

Solution 3

Some of the above suggestions are still valid for twitter bootstrap case. You can also try something like this

{{#link-to 'dashboard' tagName='li'}} 
  {{#link-to 'dashboard'}}Link Title{{/link-to}}
{{/link-to}}
  1. The link-to with li tagName applies the active class to the li
  2. The inner link-to would be a anchor element which gives you Open in New Tab functionality when right-clicked

Solution 4

Recently an Ember-cli addon came available to just do this. It is called ember-cli-active-link-wrapper.

Install: ember install ember-cli-active-link-wrapper

You can use it like this:

{{#active-link}}
  {{link-to "Index" "index"}}
{{/active-link}}

which results in:

<li class='active'>
    <a href="/" class='active'>Index</a>
</li>

Solution 5

I know this is old post, but here are updates for Ember 2.4.0

For creating links you can write

{{#link-to 'photoGallery'}}
  Great Hamster Photos
{{/link-to}}

or

{{link-to 'Great Hamster Photos' 'photoGallery'}}

Ember will automatically set class to active when current route matches link's route (in this example photoGallery).

If you want to control 'active' class on other routes as well, you can do it by setting current-when attribute.

{{#link-to 'photoGallery' current-when='photoGallery photoPreview'}}
  Great Hamster Photos
{{/link-to}}

This link will have active class on both photoGallery and photoPreview routes.

https://github.com/emberjs/ember.js/blob/v2.4.0/packages/ember-routing-views/lib/components/link-to.js#L140

Share:
24,313
coxx
Author by

coxx

Updated on July 09, 2022

Comments

  • coxx
    coxx almost 2 years

    I'm trying to create navigation tabs (taken from Twitter Bootstrap):

    <ul class="nav nav-tabs">
        <li class="active"><a href="#">Home</a></li>
        <li><a href="#">Profile</a></li>
        <li><a href="#">Messages</a></li>
    </ul>
    

    The active tab is marked with class="active".

    There is great example of static navbar and Router/Outlet feature at http://jsfiddle.net/schawaska/pfbva/, but I can't understand how to create a dynamic navbar/menu/tab view.

    As far as I understand, it is possible to use class bindings in each menu item:

     classNameBindings: ['isActive:active']
    

    But where is the right place to switch isActive attributes ?

  • Yehuda Katz
    Yehuda Katz over 11 years
    can you update your answer to reflect changes in the new router? Check out stackoverflow.com/questions/14328295/….
  • Yehuda Katz
    Yehuda Katz over 11 years
    Thanks so much @pangratz. You're a rock star.
  • Lance
    Lance over 11 years
    what if you want the tabs to change without the url changing? (while also still using the router to get to the tabs, which are at say /wizards/:wizard_id/edit and there are 3 steps to edit in the wizard which you don't want to change the url.)
  • jonnii
    jonnii about 11 years
    This needs to be the accepted answer. I just spent 10 minutes trying to get a bindAttr on an <li> tag to reference the view.href by name until I found this and realized I had it all backwards.
  • Terry
    Terry about 11 years
    @jonnii Agree, I've posted a full solution below combining the two pieces.
  • Willem de Wit
    Willem de Wit about 11 years
    This is definitely the easiest way to do it
  • Willem de Wit
    Willem de Wit about 11 years
    The problem is that this approach doesn't work with a nested menu
  • Bastes
    Bastes about 11 years
    I guess with a nested menu, you'll need some specific component to handle it for you. Anyway this is the cleanest and easiest way to do it in the context of the original question.
  • bazzel
    bazzel about 11 years
    FWIW, I updated pangratz's example as illustrated with this jsfiddle
  • Zach Riggle
    Zach Riggle about 11 years
    Definitely the best answer I found out of the group.
  • pedalpete
    pedalpete about 11 years
    This works, the only issue I'm having is that it doesn't set the default on my root link. I render my index template to my 'Intro' controller, but this doesn't set the class on the link. Any idea how to do that?
  • roman
    roman almost 11 years
    This is definately the most easiest way to do it! Should be the accepted answer.
  • Jagu
    Jagu over 10 years
    Just adding my support. A much better answer.
  • davidbuttar
    davidbuttar over 10 years
    How exactly is the poor soul who comes across my code after I've inserted this oddity supposed to know that it will insert an 'active' class in the li? Very unclear.
  • Gabriel Grant
    Gabriel Grant over 10 years
    You'll want to explicitly style your cursor to be a pointer when over the link element: a {cursor: pointer;} See marceldegraaf.net/2013/05/17/…
  • chrmod
    chrmod about 10 years
    AFAIK this solution will not work anymore as href wont be generated for a non a tags: discuss.emberjs.com/t/tagname-and-html-best-practices/4260/3
  • Simon
    Simon about 9 years
    @bazzel: Unfortunately this is not working any more.
  • Kieran Huggins
    Kieran Huggins about 9 years
    This is what we do, ideal for TWBS tabs
  • moger777
    moger777 about 9 years
    This sort of works but the href for <a> tag does not work so command + click won't open in new tabs
  • freeze
    freeze almost 9 years
    There should be better way that is not interresting, I have often to connect route logic to present logic. That is a bad way
  • Nuck
    Nuck about 8 years
    This should really be the accepted answer. All the higher-upvoted ones are broken in modern Ember or otherwise unmaintainable.
  • Simon Ihmig
    Simon Ihmig almost 8 years
    This should not be the accepted answer anymore, as this won`t work for any recent ember version. I tried the summarize the working solutions here: stackoverflow.com/a/38634312/5556104