iamjc015
iamjc015

Reputation: 2237

Modifying contents of Observable of array objects

I have the following functions inside my service:

   getFiles(): Observable<File[]> {
    const makeFiles = map((response: FileResponse[]): File[] => {
      return response.map((fileResponse: FileResponse): File => {
        return File.fromResponse(fileResponse);
      });
    });

    return this.httpService.get('/profile/files').pipe(
      makeFiles,
      shareReplay(),
    );
  }

  getFileUri(filename: string): Observable<SafeUrl> {
    return this.httpService.get(`/profile/file/uri/${filename}`).pipe(
      mergeMap((uri: string) => this.httpService.get(uri, {}, { useUrlAsItIs: true, responseType: 'arraybuffer' })),
      map((fileBuffer: any) => {
        const unsafeUrl = URL.createObjectURL(new Blob([fileBuffer], {type: 'application/binary'}));
        const safeUrl = this.sanitizer.bypassSecurityTrustUrl(unsafeUrl);

        return safeUrl;
      })
    );
  }

As you can see getFiles return Observable of File Array and getFileUri accepts filename (a property of File class) and returns Observable.

What I want to do is, combine these two functions. Meaning, getFiles() should still return Observable<File[]> and each File in the array should have safeUrl property.

My problem is, I really do not know how to do this complicated task.

Thanks!

Upvotes: 0

Views: 139

Answers (1)

martin
martin

Reputation: 96891

If you don't mind running all getFileUris in parallel you can use forkJoin to collect all responses and then update the original File objects.

import { forkJoin } from 'rxjs';

getFiles().pipe(
  mergeMap(files => {
    const observables = files.map(file => this.getFileUri(file.filename));

    return forkJoin(...observables).pipe(
      map((urls: SafeUrl[]) => {
        urls.forEach((url, index) => files[index].safeUrl = url);
        return files;
      }),
    );
  ),
}).subscribe(files => ...);

Upvotes: 1

Related Questions