Search code examples
javascriptangularhttprxjsswitchmap

using switchMap to unsubscribe previous http request and only take latest one


I'm facing an issue currently, where a first search could take 5 seconds, and second one that takes 2 seconds, problem is, the first search which takes longer, will "erase" the results of the request that was done after, because the calls ends after.

I tried to read about

switchMap

in rxJs and tried to use it, but from what I try, it doesn't unsubscribe from previous request and erases the result.

There is probably something I'm doing wrong here but I can't exactly point out what is the issue.

Merge has 3 sources of change in the result ( pagination, sorting, or new search criteria ), and the call to sendSearchCriteria returns the data used.

sendSearchCriteria returns an Observable

is there anything that comes in mind for you, that I'm doing wrong ?

Thank you for your help,

private loadDogsResults = (filtersInformation: FilterSearchCriteria) => {
    merge(this.sort.sortChange, this.paginator.page, of(filtersInformation))
      .pipe(
        distinctUntilChanged(),
        tap(() => (this.isLoading = true)),
        switchMap(() => this.sendSearchCriteria(filtersInformation)),
        //mergeMap(() => this.sendSearchCriteria(filtersInformation)),
        map(data => this.formatResults(data)),
        finalize(() => (this.isLoading = false)),
        catchError(error => this.handleError(error)),
        takeUntil(this._onDestroy$)
      )
      .subscribe((result: any[]) => {
        if (result.length > 0) {
          this.setDisplayedColumns(result[0]);
        }
        this.isLoading = false;
      });
  }

Solution

  • A colleague helped me find the issue :) we tried forkJoin, combineLatest and multiple options but biggest issue was initialization/subscription done in an odd way.

    we now created a searchTriggerSubject and added those lines

      private initializeSubscription() {
        this.searchTriggerSubscription = this.searchTriggerSubject.pipe(
          tap(() => (this.isLoading = true)),
          switchMap(() => this.sendSearchCriteria(this.claimsFilters)),
          map(data => this.formatResults(data)),
          catchError(error => this.handleError(error)),
          takeUntil(this._onDestroy$)
        ).subscribe((result: any[]) => {
        if (result.length > 0) {
          this.setDisplayedColumns(result[0]);
        }
        this.isLoading = false;
      });
      }
    
      private initializeSearchTriggerValues() {
        this.sort.sortChange.subscribe(() => this.searchTriggerSubject.next())
        this.paginator.page.subscribe(() => this.searchTriggerSubject.next())
        this.filtersSubscription = this.claimsFiltersService.getFilterValues()
        .pipe(
          filter(filters => filters !== null),
          tap((filter) => this.claimsFilters = filter)
        )
        .subscribe(() => this.searchTriggerSubject.next());
      }
    

    the filters were coming form a service so this is what we did to avoid the issue.

    Some refactoring was needed

    Thanks a lot everyone for the different leads, having multiple subjects makes it easier