Exception Handling

decorators

[Style Y110]
  • Use a decorator, at config time using the $provide service, on the $exceptionHandler service to perform custom actions when exceptions occur.

    Why?: Provides a consistent way to handle uncaught AngularJS exceptions for development-time or run-time.

    Note: Another option is to override the service instead of using a decorator. This is a fine option, but if you want to keep the default behavior and extend it a decorator is recommended.

    /* recommended */
    angular
        .module('blocks.exception')
        .config(exceptionConfig);
    
    
    exceptionConfig.$inject = ['$provide'];
    
    
    function exceptionConfig($provide) {
        $provide.decorator('$exceptionHandler', extendExceptionHandler);
    }
    
    
    extendExceptionHandler.$inject = ['$delegate', 'toastr'];
    
    
    function extendExceptionHandler($delegate, toastr) {
        return function(exception, cause) {
            $delegate(exception, cause);
            var errorData = {
                exception: exception,
                cause: cause
            };
            /**
             * Could add the error to a service's collection,
             * add errors to $rootScope, log errors to remote web server,
             * or log locally. Or throw hard. It is entirely up to you.
             * throw exception;
             */
            toastr.error(exception.msg, errorData);
        };
    }
    

Exception Catchers

[Style Y111]
  • Create a factory that exposes an interface to catch and gracefully handle exceptions.

    Why?: Provides a consistent way to catch exceptions that may be thrown in your code (e.g. during XHR calls or promise failures).

    Note: The exception catcher is good for catching and reacting to specific exceptions from calls that you know may throw one. For example, when making an XHR call to retrieve data from a remote web service and you want to catch any exceptions from that service and react uniquely.

    /* recommended */
    angular
        .module('blocks.exception')
        .factory('exception', exception);
    
    
    exception.$inject = ['logger'];
    
    
    function exception(logger) {
        var service = {
            catcher: catcher
        };
        return service;
    
    
        function catcher(message) {
            return function(reason) {
                logger.error(message, reason);
            };
        }
    }
    

Route Errors

[Style Y112]
  • Handle and log all routing errors using $routeChangeError.

    Why?: Provides a consistent way handle all routing errors.

    Why?: Potentially provides a better user experience if a routing error occurs and you route them to a friendly screen with more details or recovery options.

    /* recommended */
    function handleRoutingErrors() {
        /**
         * Route cancellation:
         * On routing error, go to the dashboard.
         * Provide an exit clause if it tries to do it twice.
         */
        $rootScope.$on('$routeChangeError',
            function(event, current, previous, rejection) {
                var destination = (current && (current.title || current.name || current.loadedTemplateUrl)) ||
                    'unknown target';
                var msg = 'Error routing to ' + destination + '. ' + (rejection.msg || '');
                /**
                 * Optionally log using a custom service or $log.
                 * (Don't forget to inject custom service)
                 */
                logger.warning(msg, [current]);
            }
        );
    }