Joel's Thoughts

Handling Error Globally - AngularJS

January 02, 2017

Handling errors on your AngularJS application ( or any software ) is a very important piece of feature to implement. This is responsible for showing a meaningful message to the user about the error. Also this should log or save detailed information about the error for future reference or troubleshooting. This is how I implement error handling on a large AngularJS project. Check-out the demo.

Let me start by creating a new module:

  angular.module('errorHandlingDemo', []);
  //....more code coming

Next on AngularJS’ global run function, I exposed 2 functions that will broadcast and emit events when invoked. These functions will be available to all the module’s controllers and views.

angular.module('errorHandlingDemo', [])
 .run(function ($rootScope) {         

                //this will broadcast Exception event to all controllers
                $rootScope.addError = function (data) {
                    this.$broadcast('Exception', data);
                };

                //this will be called from the view and will hide the exception from users
                $rootScope.closeError = function () {
                    this.$emit('hideException', null);
                };
            });

  //....more code coming

Next is to create an error manager service. I call it errorManager.

   angular.module('errorHandlingAppDemo', [])
            .run(function ($rootScope) {
                //broadcast Exception event to controllers
                $rootScope.addError = function (data) {
                    this.$broadcast('Exception', data);
                };

                //called from the view
                $rootScope.closeError = function () {
                    this.$emit('hideException', null);
                };
            })
            .factory('errorManager', function ($rootScope) {
                return {
                    //will be called when Exception occurs
                    catch: function (message) {
                        return function (reason) {
                            $rootScope.addError({ message: message, reason: reason });
                        };
                    },
                    //customize on how to display message to the user by parsing the httpResponse  
                    displayError: function (message, httpResponse) {                     

                        //for now I'm just returning the response if it's a string                    
                        if (Object.prototype.toString.call(httpResponse) === '[object String]') {
                            return httpResponse;
                        }

                        return message; //I'm just returning my own error message
                    },
                    //log error by saving to a file, saving to db etc. for future reference
                    logError: function(message, httpResponse){

                    },
                    //initiates error event listeners
                    handleError: function (scope) {
                        var oThis = this;                        
                        scope.$on('Exception', function (events, args) {
                            oThis.logError(args.message, args.reason);
                            scope.errors = oThis.displayError(args.message, args.reason);                            
                        });

                        scope.$on('hideException', function () {
                            scope.errors = null;
                        });
                    }
                };
            });

Implementations

A. Controller

Now that I have a service that manages exceptions globally, I can start using the latter on all my controllers. Let me start with my MainController.

  // ...more code before
  .controller('MainController', ['$scope', 'errorManager', '$http', function ($scope, errorManager, $http) {
                $scope.role = "Master";

                //handling error on ajax call
                $scope.submitForm = function () {                    
                    $http({
                        method: 'POST',
                        url: 'https://twitter.com/user?apiKey=fgfdgdgd'
                    }).then(function (response) {
                       console.log('Success callback says hello.');
                    }, function (httpResponse) {                      
                        errorManager.catch('An error is caught on form submission.')(httpResponse);
                    });
                };

                errorManager.handleError($scope);

            }]);

B. View

A re-usable html code ( using Bootstrap styling ) to show error message to the user. Take note of the ng-click function closeError. This will emit a hideException event to the error manager service thereby hiding the message from the view. Remember that I declare this on AngularJS module’s run function.

It’s cool that I can copy/paste the html code below on all views that will need to notify user for any exceptions making my application DRY.


  <div ng-show="errors" class="alert alert-danger alert-dismissible" role="alert">
            <a href="#" class="close" data-dismiss="alert" aria-label="close" ng-click="closeError()">&times;</a>
            <strong>Error(s):</strong>
            <p ng-bind="errors"></p>
        </div>

See the demo.









  • About
  • Search
  • Resume
  • Powered by Jekyll using the Trio theme