1

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?
Andrew Gray
  • 3,756
  • 3
  • 39
  • 75

2 Answers2

2

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.

Community
  • 1
  • 1
Andrew Gray
  • 3,756
  • 3
  • 39
  • 75
1

I had a similar problem and your post helped me find a solution. I have a common library that I use for pretty much all my common page activities like showing toast and managing the loading indicator. You solution helped to access that service using the injector. Hope this helps someone else!

// custom exception handling
module.config(function ($provide) {
    $provide.decorator('$exceptionHandler', ['$delegate', '$injector', function ($delegate, $injector) {
        return function (exception, cause) {
            $delegate(exception, cause);
            var common = $injector.get('common');
            common.toast('Whoops, an error occurred!');
            common.loading(false);
        };
    }]);
});
Brandon Johnson
  • 329
  • 5
  • 11