RxJs switchMap with angular HttpClient

mperle picture mperle · Feb 28, 2018 · Viewed 10k times · Source

I have a use case whenever a new request is triggered, any http requests that are already in flight should be cancelled / ignored.

For eg:

  • A request (say #2) comes in while the request #1 takes too long to respond / slow network connectivity.
  • In this case #2 gets a very quick response from server then at any point even if the #1 comes back with a response the HTTP response observable should be ignored.
  • The problem i face is, first the component displays response values from request #2 and gets updated again when req #1 completes (this should not happen).

I figured that switchMap cancels obervables / maintains the order in which the observable values are emitted.

excerpt from my service.ts

Obervable.of('myServiceUrl')
             .switchMap(url => this.httpRequest(url) )
              .subscribe( response => {
                   // implementation
                   /** Update an observable with the 
                       with latest changes from response. this will be 
                       displayed in a component as async */
                });


private httpRequest(url) {
        return this.httpClient.get('myUrl', { observe: 'response' });
}

The above implementation doesn't work. Could some one figure out the correct implementation for this usecase.

Answer

Explosion Pills picture Explosion Pills · Feb 28, 2018

It seems like you are creating multiple observables. It's unclear from your example, but it seems like you call Observable.of each time you want to make the request. This creates a new Observable stream each time, so for each subsequent call you get a new stream, and the previous one is not canceled. This is why .switchMap is not working.

If you want .switchMap to cancel the HTTP requests, you need them to use the same observable stream. The source Observable you want to use depends on what exactly is triggering the http requests, but you can manage it yourself using something like Subject.

const makeRequest$ = new Subject();
const myResponse$ = makeRequest$.pipe(switchMap(() => this.service.getStuff()));

You can subscribe to myResponse$ to get the response. Any time you want to trigger a request, you can do makeRequest$.next().