可观察状态(对于用户界面)

时间:2020-10-14 02:50:59

标签: angular typescript rxjs rxjs6

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

我的示例

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

网络示例

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>

1 个答案:

答案 0 :(得分: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(err => of({ 
          status: 'error', 
          value: 'ERROR MESSAGE: ' + err.message
        })),
      )
    )
  )
);