javascriptangularrxjsswitchmap

Is there a way to indicate when the RxJS operator "switchMap" discards a previous emitted item by the source Observable?


I am using an "in progress" indicator that is displayed as long as tasks are currently running. When starting a task, the tasks counter increases by 1 and decreases by 1 at the end of the task. Basically: if (count>0) displayIndicator().

When a new inner Observable is emitted, switchMap stops emitting items from the earlier-emitted inner Observable and begins emitting items from the new one.

The problem is, that disregarding earlier-emmited Observables does not trigger the counter that decreases this.uiService.indicator.task(-1).

init(): void {
    this.searchResults$: Observable<SearchResult[]> = this.searchTerms.pipe(

    // wait 700ms after each keystroke before considering the term
    debounceTime(700),

    // ignore new term if same as previous term
    distinctUntilChanged(),
      
    // switch to new search observable each time the term changes and discard previous (active) responses
    switchMap((searchTerm, i) => this.apiService.searchDB(searchTerm, i))
    );


    this.searchSubscription = this.searchResults$.subscribe({
      next: (response) => {
        console.log('received', response)
        this.uiService.indicator.task(-1);
      }
}
triggerSearch(term: string): void {
    this.searchTerms.next(term);
}
apiService.searchDB(searchTerm, i): Observable<SearchResult[]> {
    this.uiService.indicator.task(+1);
    ...
}

I've tried using the tap operator to catch it after switchMap, but it's not being triggered either since switchMap interrupts passing Observables when a new searchTerm is emitted.


Solution

  • Try using the finalize operator inside the switchMap:

    
    switchMap((searchTerm, i) => this.apiService.searchDB(searchTerm, i)).pipe(
      finalize(() => this.uiService.indicator.task(-1)
    )
    
    ...
    
    this.searchSubscription = this.searchResults$.subscribe((response) => console.log('received', response));
    
    

    Untested as I'm on mobile.