7

I have an array of image objects.

console.info('gallery', galleryArray);

enter image description here

The length of this array can be different. I have to make a POST request on every item of this array. The next request must be executed only after previous request has finished.

So I tried to make an array of Observable requests like this:

  let requests: Observable<Response>[] = [];
  galleryArray.forEach((image) => {
    requests.push(this._myService.uploadFilesImages(image));
  });

  console.info(requests);

enter image description here

My service looks like this:

uploadFilesImages(fileToUpload: any): Observable<any> {
  const input = new FormData();
  input.append('image', fileToUpload);
  return this.uploadHttp.post(`${this.endpoint}`, input)
  .map(
    (res: Response) => res.json()
  );
}

The question is how to perform those requests, so that every api call goes only after previous has finished? Help please. I'm new to Angular.

2
  • does your _myService.uploadFilesImages return any promise or observable? Commented Aug 22, 2017 at 10:17
  • 1
    @Faisal It returns observable. See edit Commented Aug 22, 2017 at 10:22

2 Answers 2

11

You are looking for the concatMap operator:

Example

const apiRoot = 'https://jsonplaceholder.typicode.com/';
const urls = [];
for (let i = 0; i < 500; i++) {
  urls.push(apiRoot + 'posts/' + (i + 1));
}
Observable.of(...urls)
  .concatMap((url: string) => this.http.get(url))
  .subscribe((result) => console.log(result));

The concatMap operator only emits after the current iterated on observable is complete. You get the results of the individual calls in the the subscribe block.

In your particular case:

 Observable.of(...galleryArray)
  .concatMap((image) => this._myService.uploadFilesImages(image))
  .subscribe((result) => console.log(result));
Sign up to request clarification or add additional context in comments.

2 Comments

Angular 7 syntax of your example import { of } from 'rxjs'; of(...urls).pipe( .concatMap((url: string) => this.http.get(url))) .subscribe((result) => console.log(result)); and thanks for your answer
This does not answer the question
2

You can use async / await for that purpose with the Promise resolve:

let requests: Observable<Response>[] = [];
galleryArray.forEach((image) => {
    await new Promise(resolve => {
        this._myService.uploadFilesImages(image)
            .subscribe(result => { 
                requests.push(result);         
                // resolve the promise once we have a result
                resolve();
            });
    });    
});

// This will only be called once all the api calls have been made
console.info(requests);

Make sure you put async behind the method where you are executing this code. Link to my answer for a similar question.

1 Comment

It seems that this is an awkward workaround, not an idiomatic way to solve this problem. In Angular every event stream is based on rxjs.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.