Breadcrumbs with Foundation in Angular


This is a compilation of some of my process notes for building a navigation breadcrumbs feature inside of an Angular application with a Foundation front-end.

app.js

Include a breadcrumbs scope variable on your application's $rootScope in app.js:

# app.js

...

// Breadcrumbs for Navigation
  $rootScope.$on('$locationChangeStart', function() {
    $rootScope.breadcrumbs = [{title: 'Home Page', href: '/home'}];
    });

...

The above function initializes on a $locationChangeStart event with a "top level breadcrumb" for the Home Page of the site. Don't forget to include the $location service when initializing the application.

HTML templates

Next, build the breadcrumbs HTML element. I used the base Foundation breadcrumbs component.

# breadcrumbs.html

<div class="row">  
  <ul class="breadcrumbs">
    <li ng-repeat="breadcrumb in breadcrumbs" ng-class="{'current': !breadcrumb.href}">
      <a ng-if="breadcrumb.href" ng-href="{{breadcrumb.href}}">{{breadcrumb.title}}</a>
      <a ng-if="!breadcrumb.href">{{breadcrumb.title}}</a>
    </li>
  </ul>
</div>  

Use <ng-include src="PATH/TO/YOUR/breadcrumbs.html"></ng-include> to include a "breadcrumbs" element on your view.

Angular Controllers

Our application uses a function to set the $scope.mode variable to 'index', 'new', 'show', or 'edit' (echoing the standard CRUD(+index) structure). That function looks like this:

# users/controller.js

...

UsersCtrl.prototype.init = function($scope, $location) {  
  // (Sets the "mode" based on the URL)

  // Default Mode: Show
  $scope.mode = 'show';

  if (/\/users$/.test($location.path())) return $scope.mode = 'index';
  if (/\/new$/.test($location.path())) return $scope.mode = 'new';
  if (/\/edit$/.test($location.path())) return $scope.mode = 'edit';
};

...

Then, we have a "fetch" function that gets the right data from the right endpoint with our User service for each view:

# users/controller.js
...
UsersCtrl.prototype.fetch = function($scope, $rootScope, $location, $routeParams, User) {

  if ($scope.mode === 'index') {
    User.list().then(function(items) {
      $scope.users = items.entities;

      // Breadcrumbs: Users
      $rootScope.breadcrumbs.push({title: 'Users'});
    });

  } else if ($scope.mode === 'new') {

    // Breadcrumbs: Users / New User
    $rootScope.breadcrumbs.push({title: 'Users', href: '/users'});
    $rootScope.breadcrumbs.push({title: 'New User'});

  } else if ($scope.mode === 'show') {
    User.get($routeParams.userId).then(function(item) {
      $scope.user = item;

      // Breadcrumbs: Users / User Name
      $rootScope.breadcrumbs.push({title: 'Users', href: '/admin/users'});
      $rootScope.breadcrumbs.push({title: $scope.user.properties.first_name + ' ' + $scope.user.properties.last_name});

    });

  } else if ($scope.mode === 'edit') {
    User.get($routeParams.userId).then(function(item) {
      $scope.user = item;

      // Breadcrumbs: Users / Update User
      $rootScope.breadcrumbs.push({title: 'Users', href: '/users'});
      $rootScope.breadcrumbs.push({title: ($scope.user.properties.first_name + ' ' + $scope.user.properties.last_name), href: '/users/' + $scope.user.properties.id});
      $rootScope.breadcrumbs.push({title: 'Update User'});

    });
  }
};
...

Each change in the window location resets the breadcrumbs when it hits that original $rootScope.$on('$locationChangeStart', function() {...} function that we wrote in app.js. Then the UserCtrl.init() function reads the URL to determine the current view and sets $scope.mode. The UserCtrl.fetch() function reads $scope.mode, then pushes hardcoded breadcrumbs into the $rootScope.breadcrumbs object as necessary. These get rendered in the HTML template!