born2net
born2net

Reputation: 24973

Angular2: how to merge rxjs calls from separate components via http service

So I use switchMap() to cancel out HTTP calls and keep only the last call to the server... Here is the service:

function httpService(url) {
   // httpRequest$ stream that allows us to push new requests
   const httpRequest$ = new Rx.Subject();

   // httpResponse$ stream that allows clients of the httpService
   // to handle our responses (fetch here can be replaced with whatever
   // http library you're using).
   const httpResponse$ = httpRequest$
       .switchMap(() => fetch(url));


   // Expose a single method get() that pushes a new
   // request onto the httpRequest stream. Expose the
   // httpResponse$ stream to handle responses.
   return {
       get: () => httpRequest$.next(),
       httpResponse$
   };
}

and the component using this service:

const http = httpService('http://my.api.com/resource');

// Subscribe to any responses
http.httpResponse$.subscribe(resp => console.log(resp));

// Call http.get() a bunch of times: should only get one log!!
http.get();
http.get();
http.get();

This works fine for one component... BUT, the issue is that if I call httpService(url) from different components I will still get MULTIPLE instances of HTTP streams, and sure, it will only be a SINGLE stream per component (due to switchMap() canceling out repetitive http.get() PER SAME component)... my goal is to have ALL calls from all components be canceled out and only the last one sent to server, be accounted for.

What I am missing is the ability to merge all the streams together from the different components inside of httpService and have switchMap() only deal with the last last last one... tricky... :/

Upvotes: 1

Views: 500

Answers (2)

born2net
born2net

Reputation: 24973

constructor(private _http:Http, private appStore:AppStore) {

    this.httpRequest$ = new Subject();


    this.httpRequest$
        .map(v=> {
            return v;
        })
        .switchMap((v:any):any => {
            console.log(v);
            if (v.id==-1||v.id=='-1')
                return 'bye, cancel all pending network calls';                
            return this._http.get('example.com)
                .map(result => {
                    var xmlData:string = result.text()
                });
        }).share()
        .subscribe(e => {                
        })
    ...

and to push data in:

this.httpRequest$.next({id: busId});        

this works great and I can now have a single service that I can pipe all network calls through as well as cancel prior calls...

see image below, as new calls come in, prior ones are canceled. note how I set slow network with a delay of 4sec to provide all is working as expected...

enter image description here

Upvotes: 0

Sasxa
Sasxa

Reputation: 41264

Don't directly return observable from request, but create observable from data. Something like this:

function httpService(url) {
   const httpRequest$ = new Rx.Subject();
   let httpResponse$ = new Rx.Subject();

   httpRequest$.switchMap(() => fetch(url)).subscribe(data => httpResponse$.next(data))

   return {
       get: () => httpRequest$.next(),
       httpResponse$
   };
}

Upvotes: 1

Related Questions