Catching errors with $exceptionHandler

Share this video with your friends

Social Share Links

Send Tweet

The AngularJS $exceptionHandler service allows you to catch and handle unanticipated JavaScript errors in a meaningful way.

[00:00] Any app that gets deployed to production should have fairly robust error handling. In this video we're going to look at how to catch some errors that would otherwise go unnoticed and possibly sneak through without you realizing something is going on.

[00:15] In this case we just have a success and a failure handler for an HTTP call that we're going to make. We're just going to load my repost from GitHub. If I go over here and actually run this, we can see, hooray, data, and there were 30 reposts found.

[00:31] What we have here is going to catch any errors with the HTTP call itself. So if it fails for any reason, that function is going to be called. The easiest way for us to simulate that is to just make our service use a URL that doesn't exist. If we rerun that, we can see, boo, error and the actual error object that we got back is traced out.

[00:59] Now, that sort of error is fairly easy to design for and to handle in a meaningful way. What is a little more subtle and a lot of times not handled properly or at all is if you have an error in your code that is running at runtime, like calling a method that doesn't exist.

[01:22] If we were to go up here to our success handler and try and call this method count on the result that obviously does not exist and then we run that, we do see we've got this error in our console here. But other than that console error, that error is not going to be logged anywhere. It's not going to be recorded. You have no way to actually react to it or handle it.

[01:49] Thankfully, however, Angular does provide a way specifically for this to catch errors that are not caught elsewhere in your app. What we are going to do is we are going to add an exception handler factory definition here. We name it $exceptionhandler. That's what Angular knows to refer to. And then we are actually going to return a function that accepts an exception and a cause argument.

[02:21] If we then save this and go run it, you can see I already ran it there once, we've got a type error object for the exception argument, and then cause is actually undefined. To be honest, cause is undefined a lot of the time. And I haven't really dug in enough to find all of the cases where that is or is not the case.

[02:43] But you can see here that the exception object does have a message property that is fairly useful to us. It at least tells us the undefined is not a function. It would be nice if it gave us the name of the function, but we'll take what we can get for now.

[02:58] What you can actually do here is you can use this to do something meaningful with these errors, whether that is display them in the UI or maybe send them to an analytics service, which is something I've done in the past, where this function will actually be run through the injector. So you could inject your Google Analytics service or your Mix panel service, or whatever the case may be and then log those things to the server and actually review them at a later time.

[03:34] What we're going to do here instead, just for simplicity's sake, we are just going to show them in the UI right now. If we inject the injector here, we can then get the root scope object by doing injector.get, root scope. And the reason that I'm not just injecting the root scope is that you actually end up with a circular reference error if you do that, because root scope apparently references exception handler. So if exception handler references root scope, you end up with that circular issue.

[04:12] We're then going to say rootscope.errors. I guess we need to make sure that we've got an array here to work with. So we'll say rootscope.errors, push. In this case we're just going to use the message property off of that exception object that we get back.

[04:38] If we then do that, let's see. First we'll just trace out the root scope errors here. If we go run this again, we see that we do have this array here of undefined is not a function. Maybe you want to do something in your UI like actually display these. I would assume this would be a dev only thing probably. But if we have an unordered list here and we say we're only going to show it if errors exist and errors has a length of at least one, and then we just iterate over the errors and show it there.

[05:17] We can then save that, go back and refresh this, and we can see that we have this error here. That's how you handle uncaught errors.