The header and footer of an application are typically outside the scope of the content or controller you're working on. This makes managing the navigation state a little more challenging. In my case, managing navigation state is simply applying an active class to a particular element.
Take the markup below for example. ng-view is the area my content controller is generating content. The problem is that when I invoke #/view1, the primary navigation is outside the scope of the view1 controller.
index.html
<html lang="en" ng-app="myApp">
<body>
<ul class="menu">
<li><a href="#/view1">view1</a></li>
<li><a href="#/view2">view2</a></li>
</ul>
<div ng-view></div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
</body>
</html>
A simple way to approach this is to wrap your navigation in its own controller, and use the $location service to detect the path.
In the code below, I added the NavCtrl
controller and injected $scope and $location. This allows us to access $location, and more specifically, $location.path, in the markup.
js/controllers.js
'use strict';
angular.module('myApp.controllers', []).
controller('NavCtrl', ['$scope', '$location', function($scope, $location) {
$scope.$location = $location;
}])
.controller('MyCtrl1', [function() {
}])
.controller('MyCtrl2', [function() {
}]);
Once the controller is in place, use the ng-controller directive to apply the controller to the navigation. Then we can use the ng-class directive to conditionally set the class based on $location.path.
The markup now looks like this:
index.html
<html lang="en" ng-app="myApp">
<body>
<ul ng-controller="NavCtrl" class="menu">
<li ng-class="{active: $location.path() == '/view1'}"><a href="#/view1">view1</a></li>
<li ng-class="{active: $location.path() == '/view2'}"><a href="#/view2">view2</a></li>
</ul>
<div ng-view></div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
</body>
</html>
You can take it a step further by managing the navigation array inside the controller, and create a function that tests if the item is equal to the current path.
js/controllers.js
'use strict';
angular.module('myApp.controllers', []).
controller('NavCtrl', ['$scope', '$location', function($scope, $location) {
$scope.items = [
{path: '/view1', title: 'View 1'},
{path: '/view2', title: 'View 2'},
];
$scope.isActive = function(item) {
if (item.path == $location.path()) {
return true;
}
return false;
};
}])
.controller('MyCtrl1', [function() {
}])
.controller('MyCtrl2', [function() {
}]);
Now that the nav item data is being managed inside the controller, you can use ng-repeat directive to set the list items and isActive() to test for the path.
index.html
<html lang="en" ng-app="myApp">
<body>
<ul ng-controller="NavCtrl" class="menu">
<li ng-repeat="item in items" ng-class="{active: isActive(item)}"><a href="#{{item.path}}">{{item.title}}</a></li>
</ul>
<div ng-view></div>
<script src="//ajax.googleapis.com/ajax/libs/angularjs/1.0.7/angular.min.js"></script>
</body>
</html>