Getting the Bootstrap 3 Navbar and AngularJS to play nicely together

13 November 2013

I ran into a couple of issues when using the Bootstrap 3 Navbar component in an AngularJS application, namely:

  • The navbar doesn't collapse automatically when the route / location is changed (applies to 'mobile' view only)
  • The active menu item isn't tracked correctly, it just stays the same when the location is changed

Here's how to fix them:

 

Collapse Bootstrap 3 Navbar on route / location change


In the HTML

Find this line:
<button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1">
And change it to:
<button type="button" class="navbar-toggle" ng-click="isCollapsed = !isCollapsed">
Then find this line:
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
And change it to:
<div class="navbar-collapse" ng-class="isCollapsed ? 'collapse' : 'in'">
Add the attribute ng-controller="NavController" to your <nav> element to hook up the Navbar to your AngularJS controller:
<nav ng-controller="NavController" class="navbar navbar-default navbar-fixed-top" role="navigation">


In the Controller

Initialise the isCollapsed variable on the $scope to true, and add an event handler on route change to reset it to true:
var app = angular.module('myapp.controllers', []);

app.controller('NavController', function ($scope, $location) {
    $scope.isCollapsed = true;
    $scope.$on('$routeChangeSuccess', function () {
        $scope.isCollapsed = true;
    });
});

 

Correctly keep track of active menu item

In the HTML

Add the attribute ng-class="getClass('[PATH]')" to each of your menu item <li> elements, eg:

<li ng-class="getClass('/')"><a href="#/">Home</a></li>
<li ng-class="getClass('/page1')"><a href="#/page1">Page 1</a></li>

 

In the Controller

Add the getClass function to the $scope, which will compare the path argument to the current location and return 'active' for the current menu item:

$scope.getClass = function (path) {
    if(path === '/') {
        if($location.path() === '/') {
            return "active";
        } else {
            return "";
        }
    }

    if ($location.path().substr(0, path.length) === path) {
        return "active";
    } else {
        return "";
    }
}

 

Note: Because this approach uses the AngularJS framework to do everything, you don't need to include the bootstrap js file in your code.