Angular Tip: HTTP request progress

AngularJS logoThe authors of AngularJS recognized the need for developers to be able to access the underlying XMLHttpRequest object used by the $http service. In version 1.4.7 they introduced a new service, called $xhrFactory, which is used by the framework to create instances of XMLHttpRequest.

That’s great! However, some use-cases remain far from being trivial. For example, let’s say that our application downloads or uploads large amounts of data and wants to display the progress information to the user. That means we need to register a “progress” event listener on the XMLHttpRequest, which is easy with the new $xhrFactory service, and then somehow relay the progress events from the listener to our AngularJS controller. This is where it becomes tricky.

The first solution that comes to mind is broadcasting the progress event on the root scope and register an event listener in the controllers. For example:

All good, but it’s somewhat a “weapon of mass destruction” as it always makes all requests broadcast all progress events to everything in the application. Having the request URL as one of the event parameters helps on the listener side to identify progress events that belong to it, but it is still awfully inefficient. Ideally, we would want to specify an optional progress listener on the HTTP call configuration object passed to $http together with the method, the URL, etc.

Fortunately for us, $http service has a property “primarily meant to be used for debugging purposes.” The property is pendingRequests, which is an array, and at the moment when $xhrFactory is called, the last element of this array will always be the responsible $http call configuration object (this is very much undocumented behavior, so please, correct me if I’m wrong!).

Here is what we can do with it:

Note, that in the $xhrFactory decorator we can’t have a declared dependency on  $http service as it introduces a circular dependency. That is why we look up the service using $injector.

1 thought on “Angular Tip: HTTP request progress

  1. thank you, helped me with download progress.
    if you want a progress bar, need to wrap code inside $scope.apply().

Comments are closed.