Andrew Gray Andrew Gray - 5 months ago 14
AngularJS Question

Circular Reference when decorating $errorProvider

On a project I'm working on, I'm working on implementing a developer notification system at my project lead's behest. The way it works, is that if a front-end error occurs, the development team gets sent an error e-mail.

However, with my current implementation, it seems I have the following circular dependency:

$rootScope <- $http <- $exceptionHandler <- $rootScope


In the following code:

(function() {
'use strict';

// Using .config to 'decorate' the exception handler.
angular.module('app').config(function($provide) {
$provide.decorator('$exceptionHandler', ['$delegate', '$http', dispatchErrorEmail]);
});

function dispatchErrorEmail($delegate, $http) {
return function (exception, cause) {
// Execute default implementation.
$delegate(exception, cause);

// Angular exceptions fail softly, but generate an error email.
var args = {
'exception': exception,
'cause': cause
};
$http.post('/api/admin/ErrorNotification', args);
};
}
})();


As you can see, there's one small problem: I'm not actually using
$rootScope
in any way whatsoever in my decoration of
$errorHandler
.


What's more, neither the
$provide.decorator
or the
$errorHandler
documentation makes any note of
$rootScope
being implicitly included.

Questions:


  1. How is
    $rootScope
    getting injected into this service, exactly?

  2. In what way can I rewrite my
    $exceptionHandler
    decoration to avoid this circular dependency?


Answer

A little additional looking around - specifically, on the Related sidebar - led me to this answer. Pretty much, I have to use $injector in order to get an instance handle of my $http service.

(function() {
   'use strict';

    // Using .config to 'decorate' the exception handler.
    angular.module('app').config(function($provide) {
        $provide.decorator('$exceptionHandler', ['$delegate', '$injector', dispatchErrorEmail]);
    });

    function dispatchErrorEmail($delegate, $injector) {
        return function (exception, cause) {
            // Execute default implementation.
            $delegate(exception, cause);

            // Angular exceptions fail softly, but generate an error email.
            var $http = $injector.get('$http');
            var args = {
                'exception': exception,
                'cause': cause
            };
            $http.post('/api/admin/ErrorNotification', args);
        };
    }
})();

This doesn't explain why $rootScope is sneaking into the $exceptionHandler service; I guess I just have to take it on faith that it does.