0

I am trying to understand rxjs (6) and how I should call conditionally make a second http post.

My scenario is that:

  1. I am/have uploaded a file.
  2. I get an object identifying the current progress and a filename.
  3. If the current progress is 100 I want to make the second http post and on success of that second call return the progress and the filename
  4. If the current progress is less than 100 simply return the progress and filename

My class

export class BasePortalDetailsManagerService {
   updateCertificate(file: File): Observable<IUploadProgress> {
    return this._azureBlobStorage
               .uploadCertificateToBlobStorage2(file, this.portalKey)
               .pipe(
                  map(progress => this.mapProgress2(progress))
                );
  }

  private mapProgress2(fileProgress: FileProgress): IUploadProgress {
    if (fileProgress.Progress === 100) {
      console.log('I can do something here but there must be a better way');

    } else {
      return {
        filename: fileProgress.FilePath,
        progress: fileProgress.Progress
      };
    }
  }   
}

I have been watching and reading various stuff and the only that seems to happen is, it convinces me my way is wrong. I cant seem to get my head round the various tutorials.

various links I've followed

rxjs quick start

cory rylan

rxjs where is the if/else

tony09uk
  • 2,841
  • 9
  • 45
  • 71
  • Something like this? https://stackoverflow.com/questions/47610150/rxjs-condition-inside-flatmap/47610715#47610715 – Oles Savluk Mar 09 '19 at 08:47

2 Answers2

0

Instead of map use concatMap and depending on progress return this original object wrapped in an Observable with of(progress) or return another Observable that makes the second request and map its result to progress:

this._azureBlobStorage.uploadCertificateToBlobStorage2(file, this.portalKey).pipe(
  concatMap(progress => progress.Progress === 100
    ? this.mapProgress2(progress).pipe(
        map(filename => ({ // This could go inside `mapProgress2` as well
          filename: progress.FilePath,
          progress: progress.Progress
        })),
      )
    : of(progress)
  ),
);
martin
  • 93,354
  • 25
  • 191
  • 226
  • Thanks for your reply. I'm feeling a little lost as I can't call pipe on mapProgress2 as it only returns IUploadProgress, not an observable. Also do I make my second http call in of or concatMap? – tony09uk Mar 09 '19 at 17:51
0

I was able to resolve my issue thanks to @martin pointing me in the right direction.

I change mapProgress2() return type to be Observable<IUploadProgress> then use flatMap to flatten the inner observable.

My knowledge of rxjs is very limited but I believe for scenario flatMap, switchMap or concatMap would suffice. @martin suggested concatMap and after reading the docs I agree.

From The RXJS docs

flatMap: flatMap is an alias for mergeMap!

mergeMap: If you would like more than one inner subscription to be maintained, try mergeMap

switchMap: If only one inner subscription should be active at a time, try switchMap

concatMap: If the order of emission and subscription of inner observables is important, try concatMap

updateCertificate(file: File): Observable<IUploadProgress> {
  return this._azureBlobStorage
             .uploadCertificateToBlobStorage2(file, this.portalKey)
             .pipe(
                flatMap(progress => this.mapProgress2(progress))
              );
}

private mapProgress2(fileProgress: IUploadProgress): Observable<IUploadProgress> {
  if (fileProgress.progress === 100) {
    return this._httpClient.post(this._portalDetails + 'certificatePath', JSON.stringify(fileProgress.filename))
               .pipe(map(res => fileProgress));
  } else {
    return Observable.create(function(observer) {
      observer.next(fileProgress);
      observer.complete();
    });
  }
}
tony09uk
  • 2,841
  • 9
  • 45
  • 71