Active menu items with AngularJS and UI-Router
I have been using AngularJS for some time now, and I really like it. Somehow I always forget what the best way is to set active classes on menu items using ui-router. So to remember this once and for all, I post my solution here. It could be useful for others as well.
UI-Router
Let’s start with the ui-router definition:
angular.module(‘app’).config(function($stateProvider) {$stateProvider
.state(‘blog’, {
abstract: true ,
url: ‘/blog’,
template: ‘<ui-view/>’
})
.state(‘blog.index’, {
url: ‘’,
templateUrl: ‘views/blog/index.html’,
controller: ‘BlogCtrl’
})
.state(‘blog.create’, {
url: ‘/create’,
templateUrl: ‘views/blog/edit.html’,
controller: ‘BlogCreateCtrl’
})
// ... etc other views such as 'show', 'edit'
The trick is to create an abstract state. I don’t want a template for this state, because this template will show on every sub-state as well. I want each state to have it’s own views-file. The url ‘/blog’ will be prepended to each sub-state.
update: the blog.index url should be ‘’, instead of ‘/’. That way the url will be site.com/blog instead of site.com/blob/ (notice the trailing slash).
Template
The view file is quite simple (when you know it):
<ul>
<li ng-class=”{ active: state.includes(‘blog’) }”>
<a ui-sref=”blog.index”>Blog</a>
</li>
</ul>
At first I tried the ui-sref-active directive but this was not working. Because the root-state is abstract, it is impossible to link to this state. By using the state.includes(‘state’) method it checks wether the requested state is in the current state list. So, the state ‘blog’ is true for every substate, such as ‘blog.index’ and ‘blog.view’.
Controller
One final trick to make it really work: $state should be attached to the scope where the menu lives. In my case I try to make directives for every menu, so the controller looks like this:
angular.module(‘app’)
.directive(‘header’, function() {
return {
restrict: ‘AE’,
templateUrl: ‘views/components/header.html’,
controller: function($rootScope, $scope, $state)
$scope.state = $state;
};
}
});When you know it, it is very simple.