Angular: Loading spinner using Http Interceptor
By: Keith Strickland
Tags: Interceptors, Angular, Loading Spinner, Typescript

I was recently working on an angular starter kit, mainly to help me understand more about the intricacies angular. I’ve been working with angular now for about 8 months and I really like how it’s structured and all the infrastructure provided with the framework. While putting this starter kit together I wanted to include a loading spinner that was smart enough to know when it should be displayed without having to manually start/stop it.

I was watching some tutorial and the topic of interceptors was brought up, specifically an Http Interceptor. What this interceptor does is allow you to intercept an HttpRequest before it’s sent to the server and after the server responds. This functionality has given me all sorts of ideas but we’ll get to those at some later date.

For the loading spinner we want to set it to loading when an http request starts and stop it once the request finishes. It should also be smart enough to handle multiple http requests and start loading when the first request is made and stop spinning when the last request is finished. So, how did I go about implementing this? I’ll show you how I did it.

First, lets start with the loading service:

So what’s going on here? This is the loading.service.ts file. There are 2 properties and 1 method here to be aware of:

loadingSub — This is a behavior subject for listening to the value of the spinner loading state. true will show the spinner, false will hide the spinner.

— This is a behavior subject for listening to the value of the spinner loading state. will show the spinner, will hide the spinner. loadingMap — This is a Map of type Map<string,boolean> . The key is a url and the value is true or false . This Map should only contain in-progress http requests. I guess I could have used an array or an object here, but a Map is the easiest to work with I believe.

— This is a Map of type . The key is a url and the value is or . This Map should only contain in-progress http requests. I guess I could have used an array or an object here, but a Map is the easiest to work with I believe. setLoading — This method accepts 2 parameters, the loading state (boolean) and a url. If the state is true , add the url to the map and update the loadingSub value. If the state is false remove the loadingMap entry with the provided url. If the loadingMap is empty, set the loadingSub value to false .

Next up is the app component.

I’ve included all 3 files for the app component. The pertinent information here is the *ngIf="loading" in app.component.html and listenToLoading in app.component.ts . The listenToLoading method subscribes to the loadingSub property of the LoadingService and updates the component’s loading property appropriately. This shows or hides the div containing the loading spinner. One piece of weirdness I encountered here was an ExpressionChangedAfterItHasBeenCheckedError exception. I had to add a delay to the loadingSub subscription to prevent that error.

The last piece of this implementation is the interceptor itself, which is pretty simple actually.

The important bit here is the intercept method. This method will be called at the start of every http request. Here we call our LoadingService.setLoading method and pass it true (for activating the spinner) and the url from the request argument. We then return the HttpHandler with the request object but include a couple of pipes.

The first pipe catches any errors and sets the spinner to false and returns the error.

The second pipe checks if the HttpEvent provided is an HttpResponse and if it is, we set our spinner to false and return the event. We can assume if we get a response from the request that the request is complete and thus safe to stop the spinner.

While developing my starter kit, this so far has worked flawlessly. This type of infrastructure makes working with angular a joy. While there is a lot to learn about the intricacies of angular, once you learn something exists the effort to implement it is fairly simple.

I hope you find this useful and until next time…. Happy coding!