Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

RxJs switchMap with angular HttpClient

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.

like image 436
mperle Avatar asked Feb 28 '18 18:02

mperle


People also ask

How does switchMap work in RxJS?

RxJS switchMap() operator is a transformation operator that applies a project function on each source value of an Observable, which is later merged in the output Observable, and the value given is the most recent projected Observable.

What is the difference between mergeMap and switchMap?

So here's the simple difference — switchMap cancels previous HTTP requests that are still in progress, while mergeMap lets all of them finish. In my case, I needed all requests to go through, as this is a metrics service that's supposed to log all actions that the user performs on the web page, so I used mergeMap .

What is the difference between switchMap concatMap and mergeMap?

Use mergeMap if you simply want to flatten the data into one Observable, use switchMap if you need to flatten the data into one Observable but only need the latest value and use concatMap if you need to flatten the data into one Observable and the order is important to you.

What is switchMap in angular RxJS?

The Angular SwitchMap maps each value from the source observable into an inner observable, subscribes to it, and then starts emitting the values from it. It creates a new inner observable for every value it receives from the Source.


2 Answers

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().

like image 100
Explosion Pills Avatar answered Oct 09 '22 21:10

Explosion Pills


I have the below code excerpt with which the switchMap implementation was successfull.

class MyClass {
    private domain: string;
    private myServiceUri: subject;
    myData$: Observable<any>;

        constructor(private http: HttpClient) {
            .....
            this.myServiceUri = new Subject();
            this.myServiceUri.switchMap(uri => {
                    return this.http.get(uri , { observe: 'response' })
                            // we have to catch the error else the observable sequence will complete
                            .catch(error => {
                                // handle error scenario
                                return Obervable.empty(); //need this to continue the stream
                            });
                    })
                    .subscribe(response => {
                        this.myData$.next(response);
                    });
        }

        getData(uri: string) {
            this.myServiceUri.next(this.domain + uri); // this will trigger the request     
        }

    }
like image 25
mperle Avatar answered Oct 09 '22 21:10

mperle