1

I have a service that is used to upload pictures. To upload a picture, all I do is

return this.http.post(/* ... */)

And I get a subscription I can subscribe to in my component. But when I want to upload several pictures, I have to do

for (let p of pics) { this.http.post(/* ... */); }

My problem is that I would like to return the results of all calls instead of just one call. Is that possible ?

EDIT Here is my service

addPictures(files: File[], folder: string): Observable<Parse.Object[]> {
  let hasError = false;
  for (let file of files) {
    let [type, ext] = file.type.split('/');
    if (type.toLowerCase() !== 'image' || !environment.imgExts.includes(ext.toLowerCase())) { hasError = true; }
  }
  if (hasError) { return Observable.throw('Invalid extension detected'); }

  let observables: Observable<Parse.Object>[] = [];

  for (let file of files) {
    // Get its size
    let img = new Image();
    img.onload = () => {
      // Create the Parse document
      let parseImg = { url: '', type: file.type, width: img.width, height: img.height };
      // Upload it on Amazon and add it to DB
      observables.push(this.addPicture(parseImg, file, folder));
    }
    img.src = window.URL.createObjectURL(file);
  }
  return Observable.forkJoin(observables);
}
  • 1
    Possible duplicate of [How to know when all Angular2 HTTP calls are finished](https://stackoverflow.com/questions/36014508/how-to-know-when-all-angular2-http-calls-are-finished) – eko Jul 25 '17 at 11:23
  • fyi, I didn't downvote the question – eko Jul 25 '17 at 11:25
  • I'm looking at this answer right now, thank you –  Jul 25 '17 at 11:29

1 Answers1

4

If you want to run all the requests in parallel you can use forkJoin():

const observables = pics.map(p => this.http.post(/* ... */));

Observable.forkJoin(observables)
  .subscribe(results => ...);

You could eventually use Observable.merge() to receive results as they arrive or eventually Observable.concat() to call requests one after another.

Graham
  • 7,431
  • 18
  • 59
  • 84
martin
  • 93,354
  • 25
  • 191
  • 226
  • It's perfectly correct, but isn't it a dupe as you'd appreciate? You can provide the answer under the dupe question as meta forum suggests :/ – eko Jul 25 '17 at 11:28
  • Well I don't know, I'm testing the solutoin given in the duplicate comment (but it looks a lot like yours). Why would I use `Observable.merge` ? I'm asking how to merge already. Forkjoin doesn't merge automatically ? –  Jul 25 '17 at 11:29
  • 1
    @trichetriche Because `forkJoin()` emits only after all the Observables completed. However `merge` emits every item from every Observable immediately. – martin Jul 25 '17 at 11:30
  • Oh I see, that means in my subscribe I will have a table of subscriptions, while with `merge` it will only be one ? –  Jul 25 '17 at 11:32
  • An array of subscription to be precise, but yes. – martin Jul 25 '17 at 11:32
  • I have an issue, I edited my post with my service, would you be able to help ? I tried putting logs under `observables.push` and they fired, but the method `addPicture` isn't triggered (this function works, I use it for a single image). Am I doing something wrong ? –  Jul 25 '17 at 11:42
  • @trichetriche `addPicture` method will only be fired after you subscribe to `addPictures` method – eko Jul 25 '17 at 11:43
  • Sorry, I subscribed to it, what I meant is that `addPictures` is called, but `addPicture` isn't. my subscription is here `this.pictureService.addPictures(ng2Files, 'ForkJoin').subscribe(data => console.log(data));` –  Jul 25 '17 at 11:46
  • In fact the problem comes from me. `addPicture` is called, but the http calls in it aren't. I'll correct that and see what happens. Anyway, the number of calls matches the number of calls I did, so your solution works. Thank you ! –  Jul 25 '17 at 11:51
  • @martin if you edit your answer, I'll retract the downvote. – eko Jul 25 '17 at 11:55