可观察状态(UI)

Observable with status (for UI)

我正在尝试创建一个具有状态的可观察对象,以便能够在 UI 中显示加载。 combineLatest 正常工作,管道仅在 switchmap 上以防止可观察对象(combineLatest)在出现错误时关闭 我找到了一个示例 ( or this),说明我应该如何使用有状态可观察对象,但我无法将两者合并,有什么帮助吗?谢谢

我的例子

combineLatest([
    Observable_One,
    Observable_Two,
    Observable_Three,
  ]).pipe(
    switchMap(([R1, R2, R3]) =>
      this.MyServiceWithPossibleError(...)
        .pipe(catchError(() => { return EMPTY }))))

Web 示例

export enum ObsevableStatus {
  SUCCESS = 'Success',
  ERROR = 'Error',
  LOADING = 'Loading',
}

export interface ObservableWithStatus<T> {
  status: string;
  data?: T;
  error?: Error;
}

export function observableWithStatus<T>(x: Observable<T>): Observable<ObservableWithStatus<T>> {
  return x.pipe(
    map(x => ({ status: ObsevableStatus.SUCCESS, data: x })),
    startWith({ status: ObsevableStatus.LOADING }),
    catchError(x => {
      return of({ status: ObsevableStatus.ERROR, error: x });
    })
  );
}

更新

  1. 如果“Observable_One”、“Observable_One”或“Observable_Three”发出一些值,则显示加载
  2. 如果我的服务 (MyWebServiceWithPossibleError) 抛出一些错误,停止加载并显示消息,但没有完成“combineLatest”(长期可观察),所以可以继续接收 3 个可观察的事件
  3. 如果没有错误,隐藏加载并显示数据

目的不是字面意义上的把两个例子结合起来,而是用两者构建一个例子

更新 2

getEntities$ = combineLatest([
    Observable_One,
    Observable_Two,
    Observable_Three,
  ]).pipe(
    switchMap(
      ([R1, R2, R3]) =>
        concat(
          of({ status: 'loading', value: '' }),
          this.MyServiceWithPossibleError$(...)
            .pipe(map(x => ({ status: 'success', value: SERVICE_RESPONSE })), catchError(() => EMPTY))
        )
    )
  )

<div *ngIf="getEntities$ | async as obs" [ngSwitch]="obs.status">
  <div *ngSwitchCase="'success'">
    Success! {{ obs.value }}
  </div>

  <div *ngSwitchCase="'error'">
    Error
  </div>

  <div *ngSwitchCase="'loading'">
    Loading!
  </div>
</div>

听起来您所缺少的只是您需要将错误映射到实际响应中,而不仅仅是一个立即完成的空流

getEntities$ = combineLatest([
  Observable_One,
  Observable_Two,
  Observable_Three
]).pipe(
  switchMap(([R1, R2, R3]) =>
    concat(
      of({ status: 'loading', value: '' }),
      this.MyServiceWithPossibleError$(...).pipe(
        map(x => ({ 
          status: 'success', 
          value: SERVICE_RESPONSE 
        })), 
        catchError(err => of({ 
          status: 'error', 
          value: 'ERROR MESSAGE: ' + err.message
        })),
      )
    )
  )
);