Konrad
Konrad

Reputation: 7208

Angular2 sequential http requests in a loop using a service

Basically what I want is something like this:

this.accounts.forEach(account=> {
   this.myService.sendMessage("hello", account).subscribe(
   success => {
       if(success)
         updateProgress...   
   })
}

The problem with this code is that it executes everything asynchronously without waiting for the previous request. I was looking at solutions using merge and flatMap but I'm confused. I'd like to wait on the request completion before moving to next iteration. This causes a problem if I want to add a progress bar.

Solution:

Basing on the other answers this is what I've come up with:

let requestList = this.accounts.map((account, index) => {
    return this.myService.sendMessage("hello", account).map(success => {
            if (success)
            {
                // Update progress here
            }
            return success;
        });
    });

Observable.concat(...requestList).subscribe(null, null, () => {
    console.log("Complete");
});

Upvotes: 0

Views: 1661

Answers (2)

Gary Holland
Gary Holland

Reputation: 2645

Here is a sample technique which may work for you.

    // create an array of promise/resolves that will sequence the calls
    let resolveArray: Array<(value: boolean) => void> = new Array[this.accounts.length];

    this.accounts.forEach((account, index) => {
        new Promise<boolean>((resolve, reject) => {
            // add the promise to the array.
            resolveArray[index] = resolve;
        }).then(result => {
            this.myService.sendMessage("hello", account).subscribe(
            success => {
                if(success)
                    // updateProgress...   

                    // when finished, resolve the next promise in the array
                    if (index < this.resolveArray.length) {
                        this.resolveArray[index + 1](true);
                    }

            })
        });
    });

    // resolve the first promise to start the resolve sequence.
    resolveArray[0](true);

This works by creating an array of promises that then trigger your subscription as each one finished.

Upvotes: 1

Julia Passynkova
Julia Passynkova

Reputation: 17879

Concat operation will sequence your requests:

let accounts = ['1', '2', '3', '4' ];

var i = 8000;
let obsList$= accounts.map(x=> {
   i = i - 1000;
  return Rx.Observable.of(x).delay(i);
});

Rx.Observable.concat(...obsList$)
   .subscribe(x=>console.log(x))
  1. map accounts to create an array of Observables. Add a delay to each one to make sure that the first ones are the slowerst one (to make sure that sequence works.
  2. Concat operator accepts a sequence of observables. so use ... (spread operator) to convert array
  3. use concat operator to make sure that next observable emits only when the previous one is completed.

Upvotes: 2

Related Questions