Here is what I ended up with, after realizing that a delay
was a good solution in terms of UX because it allowed the loader to show only when the loading time is worth displaying a loader.
I don’t like this solution because I prefer when the state is being encapsulated into Observable
operators rather than in a shared variable but I couldn’t achieve it.
counter = 0;
router.events.pipe(
filter(x => x instanceof NavigationStart),
delay(200),
).subscribe(() => {
/*
If this condition is true, then the event corresponding to the end of this NavigationStart
has not passed yet so we show the loader
*/
if (this.counter === 0) {
loaderService.show();
}
this.counter++;
});
router.events.pipe(
filter(x => x instanceof NavigationEnd || x instanceof NavigationCancel || x instanceof NavigationError)
).subscribe(() => {
this.counter--;
loaderService.hide();
});