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;
});
}
};
});
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);
}]);
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()">×</a>
<strong>Error(s):</strong>
<p ng-bind="errors"></p>
</div>
See the demo.