Angular: Loading spinner using Http Interceptor
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.loadingMap
— This is a Map of typeMap<string,boolean>
. The key is a url and the value istrue
orfalse
. 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 istrue
, add the url to the map and update the loadingSub value. If the state isfalse
remove the loadingMap entry with the provided url. If the loadingMap is empty, set the loadingSub value tofalse
.
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!