Rohit
Rohit

Reputation: 23

How to implement While loop inside RXJS subscription

I have an Angular code where in i am trying to subscribe to my 1st api and implementing a while loop inside this subscription. Further i need to subscribe to another api inside the while loop. Reason --> I need to subscribe to the inner api multiple times and the while loop should end based on a flag returned by inner api. I tried implementing the below but its not working. Need some help.

CallBanyanToFetchQuotes() {
    const url1 = 'http://ws.integration.banyantechnology.com/services/api/rest/ImportForQuote';

    this.http.post(url1, payload)
      .subscribe(importForQuoteResponse => {
        this.importForQuoteResponse = importForQuoteResponse;
        console.log('LoadID = ' + this.importForQuoteResponse.Load.Loadinfo.LoadID);
        this.loadId = this.importForQuoteResponse.Load.Loadinfo.LoadID;

        while (!this.ratingCompleted) {
          const url2 = 'http://ws.integration.banyantechnology.com/services/api/rest/GetQuotes';

          this.http.post(url2, payload)
            .subscribe(getQuoteResponse => {
              this.getQuoteResponse = getQuoteResponse;
              if (this.getQuoteResponse.RatingCompleted === true) {
                this.ratingCompleted = true;
              }
            });
        }
      });
  }

Upvotes: 1

Views: 1218

Answers (2)

frido
frido

Reputation: 14129

You can use expand to simulate a while loop. expand passes the input through to the destination immediately, maps to an Observable and receives its output as the next input. Map to EMPTY to end this recursion.

// move the urls out of the function if they are static
const url1 = 'http://ws.integration.banyantechnology.com/services/api/rest/ImportForQuote';
const url2 = 'http://ws.integration.banyantechnology.com/services/api/rest/GetQuotes';

callBanyanToFetchQuotes() {
    this.http.post(url1, payload).pipe(
      // process response from url1 http request
      tap(importForQuoteResponse => {
        this.importForQuoteResponse = importForQuoteResponse;
        console.log('LoadID = ' + this.importForQuoteResponse.Load.Loadinfo.LoadID);
        this.loadId = this.importForQuoteResponse.Load.Loadinfo.LoadID;
      }),
      // switch to url2 http request
      switchMap(_ => this.http.post(url2, payload))
      // execute url2 request again if the rating is incomplete or end execution with EMTPY
      expand(quoteResponse => quoteResponse.RatingCompleted ? EMPTY : this.http.post(url2, payload))
      // process responses from url2 requests  
    ).subscribe(quoteResponse => {
      this.getQuoteResponse = quoteResponse;
      if (quoteResponse.RatingCompleted === true) {
        this.ratingCompleted = true;
      }
    });
}

The expand approach guarantees that the next http call will be made directly and only after you received a response from the previous one.

Upvotes: 0

Eliseo
Eliseo

Reputation: 57981

this.http.post(url1, payload).pipe(
   switchMap(importForQuoteResponse=>{
      this.importForQuoteResponse = importForQuoteResponse;
      this.loadId = this.importForQuoteResponse.Load.Loadinfo.LoadID;
      return timer(0,1000).pipe(
         switchMap(()=>this.http.post(url2, payload)),
         tap(res=>this.getQuoteResponse=res),
         takeWhile(res=>!res.RatingCompleted,true),
         filter(res=>res.RatingCompleted === true)
      )
   })).subscribe(()=>{
     this.ratingCompleted = true;
   })

a "fool example" in stackblitz

the before code can be explained like: we make the first post, but, we don't want this subscribtion, so we change this subscription to a timer (switchMap). But we don't want the timer, else a second post (another switchMap). Each time timer is executed, is executed the second post and we get the response using tap. We make the call while the response was false (takeWhile) -it's important make the takewhile(...,true), the "true" makes return the last value- and filter the response (filter) so only get the "subscribe" when the response is true.

NOTE: I use timer(0,1000) to make a call each 1000 miliseconds, feel free to change the interval

Upvotes: 1

Related Questions