AngularJS Services for Dealing with Exceptions

AngularJS uses the $exceptionHandler service to handle any exceptions that arise during the execution of an application. The default implementation calls the error method defined by the $log service, which in turn calls the global console.error method.

1. Why and When to Use the Exception Service

I think of exceptions in two broad categories. The first category includes those that occur during coding and testing, which are a natural part of the development cycle and help you shape the application you are building. The other category includes those that the user sees after you have released the application to the world.

The way that you deal with these categories is different, but what’s needed in both situations is a consistent way of capturing those exceptions so that they can be responded to and, ideally, logged for future analysis. That’s where the $exceptionHandler service comes in. By default, it simply writes details of exceptions to the JavaScript console and allows the application to continue running (if that’s possible), but, as you’ll see, it can also be used to perform more sophisticated tasks, such as the ones you’ll need to keep your users happy and frustration-free when things go wrong after deployment.

Tip The $exceptionHandler service deals only with uncaught exceptions. You can catch an exception using a JavaScript try…catch block, and it will not be handled by the service.

2. Working with Exceptions

To demonstrate the $exceptionHandler service, I have added a new HTML file called exceptions.html to the angularjs folder, as shown in Listing 19-11.

Listing 19-11. The Contents of the exceptions.html File

<!DOCTYPE html>

<html ng-app=”exampleApp”>

<head>

<title>Exceptions</title>

<script src=”angular.js”></script>

<link href=”bootstrap.css” rel=”stylesheet” />

<link href=”bootstrap-theme.css” rel=”stylesheet” />

<script>

angular.module(“exampleApp”, [])

.controller(“defaultCtrl”, function ($scope) {

$scope.throwEx = function () {

throw new Error(“Triggered Exception”);

}

});

</script>

</head>

<body ng-controller=”defaultCtrl”>

<div class=”panel panel-default”>

<div class=”panel-body”>

<button class=”btn btn-primary” ng-click=”throwEx()”>Throw Exception</button>

</div>

</div>

</body>

</html>

This example contains a button element that uses the ng-click handler to trigger a controller behavior called throwEx, which throws an exception. If you load the exceptions.html file into the browser and click the button, you will see output in the JavaScript console, as follows:

Error: Triggered Exception

Depending on the browser you are using, you will also see a stack trace that includes the line number and file name of the throw statement.

3. Working Directly with the Exception Service

Although AngularJS will automatically pass exceptions to the $exceptionHandler service, you can provide more context information by working directly with the service in your code. In Listing 19-12, you can see how I have declared a dependency on the $exceptionHandler service so that I can pass my exception directly to the service.

Listing 19-12. Working Directly with the $exceptionHandler Service in the exceptions.html File

<!DOCTYPE html>

<html ng-app=”exampleApp”>

<head>

<title>Exceptions</title>

<script src=”angular.js”></script>

<link href=”bootstrap.css” rel=”stylesheet” />

<link href=”bootstrap-theme.css” rel=”stylesheet” />

<script>

angular.module(“exampleApp”, [])

.controller(“defaultCtrl”, function ($scope, $exceptionHandler) {

$scope.throwEx = function () {

try {

throw new Error(“Triggered Exception”);

} catch (ex) {

$exceptionHandler(ex.message, “Button Click”);

}

}

});

</script>

</head>

<body ng-controller=”defaultCtrl”>

<div class=”panel panel-default”>

<div class=”panel-body”>

<button class=”btn btn-primary” ng-click=”throwEx()”>Throw Exception</button>

</div>

</div>

</body>

</html>

The $exceptionHandler service object is a function that takes two arguments: the exception and an optional string describing the exception’s cause. There can be only one cause of the exception in my example, so the cause argument isn’t that useful, but if you catch an exception in a loop processing data items, for example, it can be helpful to pass details of the data item that causes the problem as the cause. Here is the output shown in the console when the button in the example is clicked:

Triggered Exception Button Click

4. Implementing a Custom Exception Handler

In Chapter 18, I cautioned you to pick distinctive service names to avoid overriding those defined by AngularJS or other packages you might be using. In this section, I am going to deliberately override the AngularJS implementation of the $errorHandler service in order to define a custom exception handling policy. In Listing 19-13, you can see how I have implemented the replacement service.

Listing 19-13. Replacing the $errorHandler Service in the exceptions.html File

<!DOCTYPE html>

<html ng-app=”exampleApp”>

<head>

<title>Exceptions</title>

<script src=”angular.js”></script>

<link href=”bootstrap.css” rel=”stylesheet” />

<link href=”bootstrap-theme.css” rel=”stylesheet” />

<script>

angular.module(“exampleApp”, [])

.controller(“defaultCtrl”, function ($scope, $exceptionHandler) {

$scope.throwEx = function () {

try {

throw new Error(“Triggered Exception”);

} catch (ex) {

$exceptionHandler(ex, “Button Click”);

}

}

})

.factory(“$exceptionHandler”, function ($log) {

return function (exception, cause) {

$log.error(“Nessage: ” + exception.message + ” (Cause: ” + cause + “)”);

}

});

</script>

</head>

<body ng-controller=”defaultCtrl”>

<div class=”panel panel-default”>

<div class=”panel-body”>

<button class=”btn btn-primary” ng-click=”throwEx()”>Throw Exception</button>

</div>

</div>

</body>

</html>

I have used the factory method, which I described in Chapter 18, to redefine the $errorHandler service object so that it better formats the message from the exception and the cause.

Tip You can replace the default behavior with something much more complex, but I recommend caution. Error handling code needs to be bullet-proof because if it contains bugs, then you won’t see the real problems in the application. The simplest error handling is generally best.

If you load the exceptions.html file into the browser and click the button, you will see the formatted output:

Message: Triggered Exception (Cause: Button Click)

Source: Freeman Adam (2014), Pro AngularJS (Expert’s Voice in Web Development), Apress; 1st ed. edition.

Leave a Reply

Your email address will not be published. Required fields are marked *