Rxjs conditionally make a second http call

感情迁移 提交于 2021-02-11 15:45:10

问题


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


回答1:


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)
  ),
);



回答2:


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();
    });
  }
}


来源:https://stackoverflow.com/questions/55072397/rxjs-conditionally-make-a-second-http-call

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!