AngularJS - Directive for Route Handling

The initial setup:

<div ng-app="app" ang-controller="AppCtrl">
  <ng-view></ng-view>
</div>
var app = angular.module('app', []);

app.config(function ($routeProvider) {
  $routeProvider
    .when('/',
    {
      templateUrl: "app.html",
      controller: "ViewCtrl"
      resolve: {
        loadData: viewCtrl.loadData
      }
    }
  )
});
app.controller("AppCtrl", function ($rootScope) {
  $rootScope.$on("$routeChangeError", 
                 function (event, current, previous, rejection) {
    console.log("failed to change routes");
  });
});

var viewCtrl = app.controller("ViewCtrl", function ($scope) {
  $scope.model = {
    message: "I'm a great app!"
  }
});

viewCtrl.loadData = function ($q, $timeout) {
  var defer = $q.defer;
  $timeout(function () {
    defer.reject("loadData"); 
  }, 2000);
  return defer.promise;
};
<h1>{{ model.message }}</h1>

An alternative way of handling this route change error is by displaying it in the UI, with a directive:

<div ng-app="app" ang-controller="AppCtrl">
  <error></error>
  <ng-view></ng-view>
</div>
});
app.directive("error", function ($rootScope) {
  return {
    restrict: "E",
    template: '<div class="alert-box alert" ng-show="isError">' +
              'Error!!!!!</div>'
    link: function (scope) {
      $rootScope.$on("$routeChangeError", 
                     function (event, current, previous, rejection) {
        scope.isError = true;
      });
    }
  }
});
app.controller("AppCtrl", function ($rootScope) {

Passing $rootScope into a directive should make you feel a little funny, as listening for a routing event doesn’t fit into the canonical purpose of a directive. However, in this case, we’re listening for an Angular event, so whichever module the listening occurs in, it will still operate normally. The canary test for appropriate usage in the directive context should be whether or not this directive will work when dropped into a different module. If it will, injecting something like $rootScope is probably fine, otherwise you should refactor so that directives are remotely modified when an event occurs rather than directly inside them.

Here, the $rootScope listener registers the same callback that exists inside AppCtrl. The callback sets the isError value in the scope, which will cause the div to show in the view through the ng-show directive.