311

If I have a navbar in bootstrap with the items

Home | About | Contact

How do I set the active class for each menu item when they are active? That is, how can I set class="active" when the angular route is at

  1. #/ for home
  2. #/about for the about page
  3. #/contact for the contact page
Rishabh
  • 3,752
  • 4
  • 47
  • 74
user1876508
  • 12,864
  • 21
  • 68
  • 105
  • possible duplicate of [Make Twitter Bootstrap navbar link active](http://stackoverflow.com/questions/11813498/make-twitter-bootstrap-navbar-link-active) – givanse Oct 25 '13 at 23:32
  • 10
    This is similar, but is not an "angular way" of highlighting the navigation buttons. – user1876508 Oct 28 '13 at 19:45
  • Possible duplicate of [Set active tab style with AngularJS](http://stackoverflow.com/questions/12295983/set-active-tab-style-with-angularjs) – Amit G Mar 29 '17 at 16:10
  • If you are using **Angular routing**, please note that the perfect answer is buried way down below: https://stackoverflow.com/a/43822400/474189. – Duncan Jones Feb 25 '18 at 06:48

26 Answers26

598

A very elegant way is to use ng-controller to run a single controller outside of the ng-view:

<div class="collapse navbar-collapse" ng-controller="HeaderController">
    <ul class="nav navbar-nav">
        <li ng-class="{ active: isActive('/')}"><a href="/">Home</a></li>
        <li ng-class="{ active: isActive('/dogs')}"><a href="/dogs">Dogs</a></li>
        <li ng-class="{ active: isActive('/cats')}"><a href="/cats">Cats</a></li>
    </ul>
</div>
<div ng-view></div>

and include in controllers.js:

function HeaderController($scope, $location) 
{ 
    $scope.isActive = function (viewLocation) { 
        return viewLocation === $location.path();
    };
}
myl
  • 6,112
  • 1
  • 13
  • 6
  • Could this be put into a header directive? – user1876508 Sep 01 '13 at 20:24
  • 1
    Yes, sure it can! That's actually how I'm using it myself :) – myl Sep 01 '13 at 20:29
  • 10
    Since I am new to this I would appreciate if you could provide an example on how to put this into a header directive, please. – mono68 Sep 20 '13 at 14:53
  • 3
    @myl Awesome answer, but I just wanted to know, what is triggering isActive() to be reevaluated? It is that the controller subscribes to changes in the location or maybe clicking the element reevaluated ng-click? – Marc M. Dec 04 '13 at 07:45
  • Could there be any problems because `HeaderController` is not being added to the controllers module of the application? Is that necessary for this controller? – Iain Mar 24 '14 at 11:21
  • inject `$location` as a dependency in directive and then use @myl `controller.js` code above inside `link:` in the directive. – Danger14 Mar 31 '14 at 22:56
  • 41
    I would suggest using `return $location.path().indexOf(viewLocation) == 0;` instead so you can catch pages with parameters as well – Sven Hecht Jul 08 '14 at 20:09
  • @SvenHecht Good suggestion, most often you want to highlight section in the navigation, not just single pages. – kontur Aug 02 '14 at 13:53
  • Isn't using a function in ngClass frowned upon? Thought it was best practice to use scoped variables? – mtpultz Sep 16 '14 at 05:16
  • This also doesn't seem to work, I appears to be one route behind each time. I have to click a link twice to get $location.path to equal my viewLocation. – mtpultz Sep 16 '14 at 05:23
  • While this works. I think the controller should not handle UI related work. Correct me if this is not a valid concern. – Khanetor Sep 22 '14 at 04:38
  • Excellent!! I just used $location.url() instead of $location.path(), to include query params. – lsborg Sep 27 '14 at 01:02
  • @myl it's working fine with me thanks,, But I just need to know why do you use one curly brackets {..} in ng-class not {{...}}.. – JS-Hero Nov 05 '14 at 11:13
  • 7
    This gets the job done but its hardly `elegant` - the route name eg `/dogs` has to be duplicated in the call to `isActive('/dogs')` – wal Nov 16 '14 at 05:09
  • 7
    If you are using UI Router, then you can use the `ui-sref-active/ui-sref-active-eq` directives, ie. `ui-sref-active-eq='active'` or `ui-sref-active='active'` to achieve the same results – Dan Apr 14 '15 at 10:48
  • 10
    @SvenHecht The concern with that logic is that a home page link (/) would match every other path. – mwotton Apr 28 '15 at 05:44
  • @SvenHecht - mwotten is correct "The concern with that logic is that a home page link (/) would match every other path." – Tom Stickel Jun 09 '15 at 21:32
  • @DanPantry your answer worked and is so much simpler than anything here. Thanks! – Batman Dec 17 '15 at 23:05
  • While it's good to see the actual code, it'd be nice to see a bit of an explanation on the code rather than a copy-paste-able code. – kovac Aug 07 '16 at 06:02
  • @Sadeep Requirement is to maintain the selected tab status. The code does the same but on the fly. When a tab is clicked and location changes, each tab's class function, i.e. isActive(), gets triggered and validates the need for 'active' class. Using a controller is the right and cleaner approach, as wal pointed out, the code doesnt follow DRY. Its also redundant to trigger the isActive() for all tabs for every click. One alternative is to make controller to maintain the json array of tab details and selected tab index. With that the html can use ng-repeat for generating
  • s in html.
  • – Rakesh Kumar Cherukuri Oct 27 '16 at 20:02
  • I'm using ui-router and @DanPantry 's suggestion is so much easier when you use it along – Bryan CS Apr 15 '17 at 05:45
  • Can I inject other class than 'active' e.g. "{ active-click: isActive('/')}" ? – Mat.Now Aug 26 '17 at 11:46
  • slightly modified version works perfect for me -> `return $location.path().includes(viewLocation)`... depending on the use case... – Ruhul Amin Nov 08 '18 at 14:15