145

I have routes set in AngularJS like this:

$routeProvider
    .when('/dashboard', {templateUrl:'partials/dashboard', controller:widgetsController})
    .when('/lab', {templateUrl:'partials/lab', controller:widgetsController})

I have some links on the topbar styled as tabs. How can I add 'active' class to a tab depending on current template or url?

Sergei Basharov
  • 51,276
  • 73
  • 200
  • 335
  • possible duplicate of [How do I implement the bootstrap navbar active class with Angular JS](http://stackoverflow.com/questions/16199418/how-do-i-implement-the-bootstrap-navbar-active-class-with-angular-js) – AJ Meyghani Oct 09 '14 at 18:55
  • 4
    @AminMeyghani How can this question be duplicate of question, that was asked almost year **later**? – Regent Oct 10 '14 at 04:34

18 Answers18

275

A way to solve this without having to rely on URLs is to add a custom attribute to every partial during $routeProvider configuration, like this:

$routeProvider.
    when('/dashboard', {
        templateUrl: 'partials/dashboard.html',
        controller: widgetsController,
        activetab: 'dashboard'
    }).
    when('/lab', {
        templateUrl: 'partials/lab.html',
        controller: widgetsController,
        activetab: 'lab'
    });

Expose $route in your controller:

function widgetsController($scope, $route) {
    $scope.$route = $route;
}

Set the active class based on the current active tab:

<li ng-class="{active: $route.current.activetab == 'dashboard'}"></li>
<li ng-class="{active: $route.current.activetab == 'lab'}"></li>
Rob Juurlink
  • 4,516
  • 3
  • 20
  • 19
  • 3
    this is the best solution I've seen so far because it supports dynamic urls like /foo/:bar. – martinpaulucci Dec 20 '12 at 17:08
  • 3
    i actually haven't been able to get this working. would you be able to provide a plnkr? – PPPaul Mar 07 '13 at 22:44
  • 9
    Just one thing: Better set `$scope.activeTab = $route.current.activetab` so that you can keep the html a little cleaner. – Christoph Apr 15 '13 at 20:12
  • 2
    This does not work in AngularJS 1.0.8. $route.current is undefined. – Catfish Nov 11 '13 at 05:25
  • 1
    @PPPaul I've put up a JSFiddle: http://jsfiddle.net/hoeferh/gUPgn/ – I can't get the improvement by Christoph to work though, as the current route is undefined before the default redirect. – Henning Dec 25 '13 at 17:26
  • 2
    Combine this with @Lucas's `$rootScope` trick below to make it available in all scopes. – colllin Jan 21 '14 at 17:54
  • This code using ui-router, in last version of in directive ui-sref-active exists. No need to write you own one. – Yevgeniy Shchemelev Mar 27 '14 at 08:43
  • 1
    Invented the same solution by myself :) Of course I think it's the best one, ha-ha $route.current indeed may be undefined at the moment of initialization of the controller. But it will become available later. That's why you can not assign `$scope.activeTab = $route.current.activeTab` in the controller code. But you can export $route to $scope and use $route.current.activeTab in the html – Sergey P. aka azure Aug 21 '14 at 08:08
  • @Rob Juurlink Is it legal to add custom attribute like this ?, or it is better to add data object like https://github.com/angular-ui/ui-router/wiki#attach-custom-data-to-state-objects – George Botros Feb 01 '16 at 10:54
  • This is a good solution, but angular check "==" operation two many times, so it is maybe not elegant. – SetupX May 05 '16 at 11:11
  • @Henning....You have used only one controller for all the three partials....could you show how to do it with seperate controllers for each partial? – Sabyasachi Aug 03 '16 at 15:31
  • I expose my $route on $rootScope, because some routes did not have a Controller, then I add in my app config, the run function, this is the complete code `angular.module("myApp", ['AService', 'ngRoute']) .config(['$routeProvider', function($routeProvider){ ... //my routes configurations }]).run(function($route, $rootScope){ $rootScope.$route = $route; });` – William Miranda de Jesus Aug 11 '17 at 18:07
134

One way of doing this would be by using ngClass directive and the $location service. In your template you could do:

ng-class="{active:isActive('/dashboard')}"

where isActive would be a function in a scope defined like this:

myApp.controller('MyCtrl', function($scope, $location) {
    $scope.isActive = function(route) {
        return route === $location.path();
    }
});

Here is the complete jsFiddle: http://jsfiddle.net/pkozlowski_opensource/KzAfG/

Repeating ng-class="{active:isActive('/dashboard')}" on each navigation tab might be tedious (if you've got many tabs) so this logic might be a candidate for a very simple directive.

pkozlowski.opensource
  • 117,202
  • 60
  • 326
  • 286
  • 1
    It took me a long time before I found 'very simple directives' to actually be very simple to write, so I've provided one below. :-) It should be reusable in a variety of contexts, with no non-declarative configuration. – XML Jul 05 '13 at 20:05
  • 1
    Looking at the jsFiddle, how do you set the current page active on page load? The example only works when a user clicks an option. For example, you may want a 'home' nav highlighted when landing on the homepage from an external link. – thathurtabit Oct 14 '13 at 11:06
  • Ahh was scratching my head for a little bit on this. Thanks! – masterwok Jan 04 '15 at 06:54
41

Following Pavel's advice to use a custom directive, here's a version that requires adding no payload to the routeConfig, is super declarative, and can be adapted to react to any level of the path, by simply changing which slice() of it you're paying attention to.

app.directive('detectActiveTab', function ($location) {
    return {
      link: function postLink(scope, element, attrs) {
        scope.$on("$routeChangeSuccess", function (event, current, previous) {
            /*  
                Designed for full re-usability at any path, any level, by using 
                data from attrs. Declare like this: 
                <li class="nav_tab">
                  <a href="#/home" detect-active-tab="1">HOME</a>
                </li> 
            */

            // This var grabs the tab-level off the attribute, or defaults to 1
            var pathLevel = attrs.detectActiveTab || 1,
            // This var finds what the path is at the level specified
                pathToCheck = $location.path().split('/')[pathLevel] || 
                  "current $location.path doesn't reach this level",
            // This var finds grabs the same level of the href attribute
                tabLink = attrs.href.split('/')[pathLevel] || 
                  "href doesn't include this level";
            // Above, we use the logical 'or' operator to provide a default value
            // in cases where 'undefined' would otherwise be returned.
            // This prevents cases where undefined===undefined, 
            // possibly causing multiple tabs to be 'active'.

            // now compare the two:
            if (pathToCheck === tabLink) {
              element.addClass("active");
            }
            else {
              element.removeClass("active");
            }
        });
      }
    };
  });

We're accomplishing our goals by listening for the $routeChangeSuccess event, rather than by placing a $watch on the path. I labor under the belief that this means the logic should run less often, as I think watches fire on each $digest cycle.

Invoke it by passing your path-level argument on the directive declaration. This specifies what chunk of the current $location.path() you want to match your href attribute against.

<li class="nav_tab"><a href="#/home" detect-active-tab="1">HOME</a></li>

So, if your tabs should react to the base-level of the path, make the argument '1'. Thus, when location.path() is "/home", it will match against the "#/home" in the href. If you have tabs that should react to the second level, or third, or 11th of the path, adjust accordingly. This slicing from 1 or greater will bypass the nefarious '#' in the href, which will live at index 0.

The only requirement is that you invoke on an <a>, as the element is assuming the presence of an href attribute, which it will compare to the current path. However, you could adapt fairly easily to read/write a parent or child element, if you preferred to invoke on the <li> or something. I dig this because you can re-use it in many contexts by simply varying the pathLevel argument. If the depth to read from was assumed in the logic, you'd need multiple versions of the directive to use with multiple parts of the navigation.


EDIT 3/18/14: The solution was inadequately generalized, and would activate if you defined an arg for the value of 'activeTab' that returned undefined against both $location.path(), and the element's href. Because: undefined === undefined. Updated to fix that condition.

While working on that, I realized there should have been a version you can just declare on a parent element, with a template structure like this:

<nav id="header_tabs" find-active-tab="1">
    <a href="#/home" class="nav_tab">HOME</a>
    <a href="#/finance" class="nav_tab">Finance</a>
    <a href="#/hr" class="nav_tab">Human Resources</a>
    <a href="#/quarterly" class="nav_tab">Quarterly</a>
</nav>

Note that this version no longer remotely resembles Bootstrap-style HTML. But, it's more modern and uses fewer elements, so I'm partial to it. This version of the directive, plus the original, are now available on Github as a drop-in module you can just declare as a dependency. I'd be happy to Bower-ize them, if anybody actually uses them.

Also, if you want a bootstrap-compatible version that includes <li>'s, you can go with the angular-ui-bootstrap Tabs module, which I think came out after this original post, and which is perhaps even more declarative than this one. It's less concise for basic stuff, but provides you with some additional options, like disabled tabs and declarative events that fire on activate and deactivate.

XML
  • 19,206
  • 9
  • 64
  • 65
  • 4
    I couldn't believe no one actually give this a vote ! Here's my 2 cents. Though there's a small mistake in the code, I think the 'tabLevel' is supposed to be 'activeTab'. And for Bootstrap style, you might want to add the 'active' class to the LI element instead of the A element. But this only requires minor change. – David Lin Jul 19 '13 at 00:51
  • 1
    You are absolutely correct about activeTab, @DavidLin. Edited. But, I'm not in love with Bootstrap's structure, hence a deliberate difference there. In fact, I'm beginning to think that nav abstractions may not belong in `ul`'s at all, and perhaps should just be collections of anchors, wrapped by a `nav` or other grouping element. Dealing with the intermediary layer of `li`'s is added complexity with no payoff, particularly now that we have the `nav` element at our disposal to make it clear what's going on. – XML Jul 19 '13 at 18:04
  • This is simple and brilliant. I was surprised there wasn't something like this already in Angular for checking the route that you're on. – creamcheese Nov 23 '13 at 16:56
  • 1
    To make it work with bootstrap3, all you have to do is change ` element.addClass("active");` to ` element.parent('li').addClass("active");` I think it could be better named though, something like **is-active-tab** insead of **active-tab** which seems to declare the tab is active. Otherwise, this is a seriously nice directive. See this change in the answer by @domi – boatcoder Dec 09 '13 at 05:37
  • Best solution on this page, can't believe it has so little upvotes. – Karolis Jan 07 '14 at 12:50
  • This seems like a great solution. It works for me to update the url when I click a tab, but not if I load the page with a tab's url, it always loads the first tab. – DrCord Jan 14 '14 at 04:01
  • Works for me and doesn't pollute anything, just gently sits in a directive. Good job! – Mars Robertson Jan 24 '14 at 00:06
27

@rob-juurlink I improved a bit on your solution:

instead of each route needing an active tab; and needing to set the active tab in each controller I do this:

var App = angular.module('App',[]);
App.config(['$routeProvider', function($routeProvider){
  $routeProvider.
  when('/dashboard', {
    templateUrl: 'partials/dashboard.html',
    controller: Ctrl1
  }).
  when('/lab', {
    templateUrl: 'partials/lab.html',
    controller: Ctrl2
  });
}]).run(['$rootScope', '$location', function($rootScope, $location){
   var path = function() { return $location.path();};
   $rootScope.$watch(path, function(newVal, oldVal){
     $rootScope.activetab = newVal;
   });
}]);

And the HTML looks like this. The activetab is just the url that relates to that route. This just removes the need to add code in each controller (dragging in dependencies like $route and $rootScope if this is the only reason they're used)

<ul>
    <li ng-class="{active: activetab=='/dashboard'}">
       <a href="#/dashboard">dashboard</a>
    </li>
    <li ng-class="{active: activetab=='/lab'}">
       <a href="#/lab">lab</a>
    </li>
</ul>
EpokK
  • 38,062
  • 9
  • 61
  • 69
Lucas
  • 3,323
  • 4
  • 28
  • 34
  • Many thanks for this modification. Very nice. Do you have any suggestions for setting an active tab when the page first loads? – Hairgami_Master Apr 03 '13 at 14:39
  • 2
    depends on what you want. typically you'd have '/' url be your main controller. that way when the user goes to your url, it will load that controller and set that tab as active. In the example above I don't have a '/' url, so if thats your case simply add a .otherwise() $routeProvider. when('/dashboard', { templateUrl: 'partials/dashboard.html', controller: Ctrl1 }). when('/lab', { templateUrl: 'partials/lab.html', controller: Ctrl2 }).otherwise({ redirectTo: '/dashboard' }); best of luck! – Lucas Apr 04 '13 at 10:29
  • Many thanks @Lucas. That helped. Some reason I had to add the # symbol to my main route- when('#/', { controller: FormsController, templateUrl: 'partials/dashboard.html' }). – Hairgami_Master Apr 05 '13 at 20:55
  • I prefer this way. Having a rootScope and do anything in wherever – wrivas Aug 01 '15 at 18:12
16

Maybe a directive like this is might solve your problem: http://jsfiddle.net/p3ZMR/4/

HTML

<div ng-app="link">
<a href="#/one" active-link="active">One</a>
<a href="#/two" active-link="active">One</a>
<a href="#" active-link="active">home</a>


</div>

JS

angular.module('link', []).
directive('activeLink', ['$location', function(location) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs, controller) {
            var clazz = attrs.activeLink;
            var path = attrs.href;
            path = path.substring(1); //hack because path does bot return including hashbang
            scope.location = location;
            scope.$watch('location.path()', function(newPath) {
                if (path === newPath) {
                    element.addClass(clazz);
                } else {
                    element.removeClass(clazz);
                }
            });
        }

    };

}]);
colllin
  • 9,442
  • 9
  • 49
  • 65
kfis
  • 4,739
  • 22
  • 19
  • 1
    Note that you have to use $observe if the href contains an expression: http://docs.angularjs.org/guide/directive#Attributes. See updated fiddle: http://jsfiddle.net/p3ZMR/10/ – Narretz Oct 03 '12 at 16:14
14

Simplest solution here:

How to set bootstrap navbar active class with Angular JS?

Which is:

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();
    };
}
Community
  • 1
  • 1
Zymotik
  • 6,412
  • 3
  • 39
  • 48
12

I recommend using the state.ui module which not only support multiple and nested views but also make this kind of work very easy (code below quoted) :

<ul class="nav">
    <li ng-class="{ active: $state.includes('contacts') }"><a href="#{{$state.href('contacts')}}">Contacts</a></li>
    <li ng-class="{ active: $state.includes('about') }"><a href="#{{$state.href('about')}}">About</a></li>
</ul>

Worth reading.

David Lin
  • 13,168
  • 5
  • 46
  • 46
4

Here's another version of XMLillies w/ domi's LI change that uses a search string instead of a path level. I think this is a little more obvious what's happening for my use case.

statsApp.directive('activeTab', function ($location) {
  return {
    link: function postLink(scope, element, attrs) {
      scope.$on("$routeChangeSuccess", function (event, current, previous) {
        if (attrs.href!=undefined) { // this directive is called twice for some reason
          // The activeTab attribute should contain a path search string to match on.
          // I.e. <li><a href="#/nested/section1/partial" activeTab="/section1">First Partial</a></li>
          if ($location.path().indexOf(attrs.activeTab) >= 0) {
            element.parent().addClass("active");//parent to get the <li>
          } else {
            element.parent().removeClass("active");
          }
        }
      });
    }
  };
});

HTML now looks like:

<ul class="nav nav-tabs">
  <li><a href="#/news" active-tab="/news">News</a></li>
  <li><a href="#/some/nested/photos/rawr" active-tab="/photos">Photos</a></li>
  <li><a href="#/contact" active-tab="/contact">Contact</a></li>
</ul>
Dave Rapin
  • 1,471
  • 14
  • 18
3

I found XMLilley's anwser the best and most adaptable and non-intrusive.

However I had a small glitch.

For use with bootstrap nav, here is how I modified it:

app.directive('activeTab', function ($location) {
    return {
      link: function postLink(scope, element, attrs) {
        scope.$on("$routeChangeSuccess", function (event, current, previous) {
            /*  designed for full re-usability at any path, any level, by using 
                data from attrs
                declare like this: <li class="nav_tab"><a href="#/home" 
                                   active-tab="1">HOME</a></li> 
            */
            if(attrs.href!=undefined){// this directive is called twice for some reason
                // this var grabs the tab-level off the attribute, or defaults to 1
                var pathLevel = attrs.activeTab || 1,
                // this var finds what the path is at the level specified
                    pathToCheck = $location.path().split('/')[pathLevel],
                // this var finds grabs the same level of the href attribute
                    tabLink = attrs.href.split('/')[pathLevel];
                // now compare the two:
                if (pathToCheck === tabLink) {
                  element.parent().addClass("active");//parent to get the <li>
                }
                else {
                  element.parent().removeClass("active");
                }
            }
        });
      }
    };
  });

I added "if(attrs.href!=undefined)" because this function is apprently called twice, the second time producing an error.

As for the html:

<ul class="nav nav-tabs">
   <li class="active" active-tab="1"><a href="#/accueil" active-tab="1">Accueil</a></li>
   <li><a active-tab="1" href="#/news">News</a></li>
   <li><a active-tab="1" href="#/photos" >Photos</a></li>
   <li><a active-tab="1" href="#/contact">Contact</a></li>
</ul>
domi
  • 521
  • 1
  • 4
  • 12
  • nvm, it was my fault this was called twice. I guess "if(attrs.href!=undefined)" is not needed. – domi Oct 17 '13 at 08:48
3

Bootstrap example.

If you are using Angulars built in routing (ngview) this directive can be used:

angular.module('myApp').directive('classOnActiveLink', [function() {
    return {
        link: function(scope, element, attrs) {

            var anchorLink = element.children()[0].getAttribute('ng-href') || element.children()[0].getAttribute('href');
            anchorLink = anchorLink.replace(/^#/, '');

            scope.$on("$routeChangeSuccess", function (event, current) {
                if (current.$$route.originalPath == anchorLink) {
                    element.addClass(attrs.classOnActiveLink);
                }
                else {
                    element.removeClass(attrs.classOnActiveLink);
                }
            });

        }
    };
}]);

Assuming your markup looks like this:

    <ul class="nav navbar-nav">
        <li class-on-active-link="active"><a href="/orders">Orders</a></li>
        <li class-on-active-link="active"><a href="/distributors">Distributors</a></li>
    </ul>

I like this was of doing it since you can set the class name you want in your attribute.

David Y. Stephenson
  • 872
  • 4
  • 22
  • 44
Michael Falck Wedelgård
  • 2,943
  • 1
  • 27
  • 39
2

You can also simply inject the location into the scope and use that to deduct the style for the navigation:

function IndexController( $scope, $rootScope, $location ) {
  $rootScope.location = $location;
  ...
}

Then use it in your ng-class:

<li ng-class="{active: location.path() == '/search'}">
  <a href="/search">Search><a/>
</li>
Oliver Salzburg
  • 21,652
  • 20
  • 93
  • 138
2

an alternative way is to use ui-sref-active

A directive working alongside ui-sref to add classes to an element when the related ui-sref directive's state is active, and removing them when it is inactive. The primary use-case is to simplify the special appearance of navigation menus relying on ui-sref, by having the "active" state's menu button appear different, distinguishing it from the inactive menu items.

Usage:

ui-sref-active='class1 class2 class3' - classes "class1", "class2", and "class3" are each added to the directive element when the related ui-sref's state is active, and removed when it is inactive.

Example:
Given the following template,

<ul>
  <li ui-sref-active="active" class="item">
    <a href ui-sref="app.user({user: 'bilbobaggins'})">@bilbobaggins</a>
  </li>
  <!-- ... -->
</ul>

when the app state is "app.user", and contains the state parameter "user" with value "bilbobaggins", the resulting HTML will appear as

<ul>
  <li ui-sref-active="active" class="item active">
    <a ui-sref="app.user({user: 'bilbobaggins'})" href="/users/bilbobaggins">@bilbobaggins</a>
  </li>
  <!-- ... -->
</ul>

The class name is interpolated once during the directives link time (any further changes to the interpolated value are ignored). Multiple classes may be specified in a space-separated format.

Use ui-sref-opts directive to pass options to $state.go(). Example:

<a ui-sref="home" ui-sref-opts="{reload: true}">Home</a>
George Botros
  • 4,127
  • 3
  • 28
  • 50
1

I agree with Rob's post about having a custom attribute in the controller. Apparently I don't have enough rep to comment. Here's the jsfiddle that was requested:

sample html

<div ng-controller="MyCtrl">
    <ul>
        <li ng-repeat="link in links" ng-class="{active: $route.current.activeNav == link.type}"> <a href="{{link.uri}}">{{link.name}}</a>

        </li>
    </ul>
</div>

sample app.js

angular.module('MyApp', []).config(['$routeProvider', function ($routeProvider) {
    $routeProvider.when('/a', {
        activeNav: 'a'
    })
        .when('/a/:id', {
        activeNav: 'a'
    })
        .when('/b', {
        activeNav: 'b'
    })
        .when('/c', {
        activeNav: 'c'
    });
}])
    .controller('MyCtrl', function ($scope, $route) {
    $scope.$route = $route;
    $scope.links = [{
        uri: '#/a',
        name: 'A',
        type: 'a'
    }, {
        uri: '#/b',
        name: 'B',
        type: 'b'
    }, {
        uri: '#/c',
        name: 'C',
        type: 'c'
    }, {
        uri: '#/a/detail',
        name: 'A Detail',
        type: 'a'
    }];
});

http://jsfiddle.net/HrdR6/

jasontwong
  • 29
  • 2
  • I like the data-driven approach to the list of links. And, some may choose to move the array of links into a service/factory. – Grant Lindsay May 05 '15 at 21:17
1
'use strict';

angular.module('cloudApp')
  .controller('MenuController', function ($scope, $location, CloudAuth) {
    $scope.menu = [
      {
        'title': 'Dashboard',
        'iconClass': 'fa fa-dashboard',
        'link': '/dashboard',
        'active': true
      },
      {
        'title': 'Devices',
        'iconClass': 'fa fa-star',
        'link': '/devices'
      },
      {
        'title': 'Settings',
        'iconClass': 'fa fa-gears',
        'link': '/settings'
      }
    ];
    $location.path('/dashboard');
    $scope.isLoggedIn = CloudAuth.isLoggedIn;
    $scope.isAdmin = CloudAuth.isAdmin;
    $scope.isActive = function(route) {
      return route === $location.path();
    };
  });

And use the below in the template:

<li role="presentation" ng-class="{active:isActive(menuItem.link)}" ng-repeat="menuItem in menu"><a href="{{menuItem.link}}"><i class="{{menuItem.iconClass}}"></i>&nbsp;&nbsp;{{menuItem.title}}</a></li>
Yeshodhan Kulkarni
  • 2,844
  • 1
  • 16
  • 19
0

I needed a solution that doesn't require changes to controllers, because for some pages we only render templates and there's no controller at all. Thanks to previous commenters who suggested using $routeChangeSuccess I came up with something like this:

# Directive
angular.module('myapp.directives')
.directive 'ActiveTab', ($route) ->
  restrict: 'A'

  link: (scope, element, attrs) ->
    klass = "active"

    if $route.current.activeTab? and attrs.flActiveLink is $route.current.activeTab
      element.addClass(klass)

    scope.$on '$routeChangeSuccess', (event, current) ->
      if current.activeTab? and attrs.flActiveLink is current.activeTab
        element.addClass(klass)
      else
        element.removeClass(klass)

# Routing
$routeProvider
.when "/page",
  templateUrl: "page.html"
  activeTab: "page"
.when "/other_page",
  templateUrl: "other_page.html"
  controller: "OtherPageCtrl"
  activeTab: "other_page"

# View (.jade)
a(ng-href='/page', active-tab='page') Page
a(ng-href='/other_page', active-tab='other_page') Other page

It doesn't depend on URLs and thus it's really easy to set it up for any sub pages etc.

szimek
  • 6,404
  • 5
  • 32
  • 36
0

I can't remember where I found this method, but it's pretty simple and works well.

HTML:

<nav role="navigation">
    <ul>
        <li ui-sref-active="selected" class="inactive"><a ui-sref="tab-01">Tab 01</a></li> 
        <li ui-sref-active="selected" class="inactive"><a ui-sref="tab-02">Tab 02</a></li>
    </ul>
</nav>

CSS:

  .selected {
    background-color: $white;
    color: $light-blue;
    text-decoration: none;
    border-color: $light-grey;
  } 
cfranklin
  • 1,500
  • 1
  • 13
  • 14
0

If you're using ngRoute (for routing) then your application will have below configuration,

angular
  .module('appApp', [
    'ngRoute'
 ])
config(function ($routeProvider) {
    $routeProvider
      .when('/', {
        templateUrl: 'views/main.html',
        controller: 'MainCtrl',
        controllerAs: 'main'
      })
      .when('/about', {
        templateUrl: 'views/about.html',
        controller: 'AboutCtrl',
        controllerAs: 'about'
      })
}
});

Now, just add a controller in this configuration just like below,

angular
      .module('appApp', [
        'ngRoute'
     ])
    config(function ($routeProvider) {
        $routeProvider
          .when('/', {
            templateUrl: 'views/main.html',
            controller: 'MainCtrl',
            activetab: 'main'
          })
          .when('/about', {
            templateUrl: 'views/about.html',
            controller: 'AboutCtrl',
            activetab: 'about'
          })
    }
    })
  .controller('navController', function ($scope, $route) {
    $scope.$route = $route;
  });

As you've mentioned active tab in your configuration, now you just have to add active class in your <li> or <a> tag. Like,

ng-class="{active: $route.current.activetab == 'about'}"

Which means, whenever user click on about page, this will automatically identify the current tab and apply active css class.

I hope this helps!

imbond
  • 2,030
  • 1
  • 20
  • 22
-3

Came here for solution .. though above solutions are working fine but found them little bit complex unnecessary. For people who still looking for a easy and neat solution, it will do the task perfectly.

<section ng-init="tab=1">
                <ul class="nav nav-tabs">
                    <li ng-class="{active: tab == 1}"><a ng-click="tab=1" href="#showitem">View Inventory</a></li>
                    <li ng-class="{active: tab == 2}"><a ng-click="tab=2" href="#additem">Add new item</a></li>
                    <li ng-class="{active: tab == 3}"><a ng-click="tab=3" href="#solditem">Sold item</a></li>
                </ul>
            </section>
MGA
  • 511
  • 2
  • 11