Search code examples
angularhttpclient

Using Angular HttpClient inside for loop


I have some issues with Angular's HttpClient:

So, the app logic looks like: component.ts:

I need to call createNewVideoUploadId() from service to get ID for upload video. Than I need to send file to Service Method:

uploadVideoToApi() {
    this.lessonService.createNewVideoUploadId()
        .subscribe(res => {
            this.lessonService.uploadNewVideo(this.videoToUpload, res['X-Upload-File-ID'])
        })
}

lessonService look like:

createNewVideoUploadId() {
    return this.http.get<string>(`${environment.apiUrl}/upload/id`)
}

uploadNewVideo:

uploadNewVideo(video: File, id: string) {

    const chunkSize = 10 * 1024 ** 2;
    const count = Math.ceil(video.size / chunkSize);

    let calls = []

    for (let i = 0; i < count; i++) {
        let chunk = video.slice(i * chunkSize, (i + 1) * chunkSize);

        let fd = new FormData();
        fd.append('file', chunk);
        fd.append('file_name', video.name);
        fd.append('file_size', video.size.toString());
        fd.append('chunk_size', chunkSize.toString());
        fd.append('chunk_number', i.toString());
        fd.append('chunks_count', count.toString());

        return this.http.post(`${environment.apiUrl}/upload/${id}`, fd)
    }
} // uploadNewVideo()

So, for loop is stopping in first iteration because of return

I need to execute each for loop iteration one by one from component.ts

So, I need to subscribe to uploadNewVideo, and get responses. But I cant return anything from cycle.


Solution

  • You could RxJS forkJoin() method. Try the following

    uploadNewVideo(video: File, id: string) {
      const chunkSize = 10 * 1024 ** 2;
      const count = Math.ceil(video.size / chunkSize);
      let calls = []
    
      for (let i = 0; i < count; i++) {
        let chunk = video.slice(i * chunkSize, (i + 1) * chunkSize);
    
        let fd = new FormData();
        fd.append('file', chunk);
        fd.append('file_name', video.name);
        fd.append('file_size', video.size.toString());
        fd.append('chunk_size', chunkSize.toString());
        fd.append('chunk_number', i.toString());
        fd.append('chunks_count', count.toString());
    
        calls.push(this.http.post(`${environment.apiUrl}/upload/${id}`, fd).pipe(retry(3)))   // <-- retry 3x in case of error
      }
    
      return forkJoin(calls);     // <-- use `forkJoin` here
    }
    

    Now you could subscribe to the function to trigger the calls

    uploadVideoToApi() {
      this.lessonService.createNewVideoUploadId().pipe(
        switchMap(res => this.lessonService.uploadNewVideo(this.videoToUpload, res['X-Upload-File-ID'])),
        catchError(error => of(error))
      ).subscribe(
        response => {
          // handle response
        },
        error => {
          // handle error
        }
      );
    }