I'm trying to build a pluggable ProgressService.
The service should track how many "things" are currently loading. And have an isLoading() method that returns an Observable<boolean> to indicate if anything is loading at all.
My first solution was very naive using a new BehaviorSubject(0) and then each loading provider just called ProgressService.increase() and ProgressService.decrease(). This worked fine. But now I'd like to go more reactive, if possible.
Then I came across merge, which works fine when all loading providers are known at the beginning:
this.progress = merge(...progressProviders).pipe(
scan((acc, curr) => acc + (curr ? 1 : -1), 0)
);
This will simply increase / decrease the progress value, when any loading provider emits true or false.
But I also need some kind of register / unregister functionality. This should basically add a new Observable to the merge chain (or remove it).
The new ProgressService should look like this:
class ProgressService {
progress: Observable<number> = EMPTY; // value > 0 when something is loading
addLoadingProvider(lp: Observable<boolean>) {
// increment this.progress, when lp emits true
// decrease this.progress, when lp emits false
// nice to have: ignore if lp's first emitted value is false
}
removeLoadingProvider(lp: Observable<boolean>) {
// stop listening to lp
// clean up: decrease this.progress, if lp last emitted true
}
isLoading(): Observable<boolean> {
return this.progress.pipe(
map(val => val !== 0)
);
}
}
Maybe the removeLoadingProvider method isn't needed at all (?), if we return a Subscription from addLoadingProvider, and use Subscription.unsubscribe() to unregister.
Hopefully someone can tell me how to merge and unmerge additional Observables on demand.