Angular 2 - 当(observableData | async)尚未解析时显示加载信息

Ale*_*ski 14 observable rxjs typescript angular

正如标题所说,我想拥抱rxjs Observables的力量.

我现在应该做什么:

// dataview.html
<div *ngIf="isLoading">Loading data...div>
<ul *ngIf="!isLoading">
    <li *ngFor="let d of data">{{ d.value }}</li>
</ul>


// dataview.ts

data: any[] = [];
isLoading: boolean = false;

getData() {

this.isLoading = true;
this._api.getData().subscribe(
        data => {
            this.data = data;
            this.isLoading = false;
        },
        error => {
            this.error = error;
            this.isLoading = false;
        });
}
Run Code Online (Sandbox Code Playgroud)

我想做的事:

1. async在我的模板中使用管道

  1. 创建data一个Observable数组

  2. 仍显示用户的加载信息

我是干净代码的忠实粉丝,那么如何使用rxjs和Angular 2很好地完成这项工作呢?

Kli*_*ent 13

我就是这样做的.我也使用$和变量名称来提醒我它是一个流.

// dataview.html
<div *ngIf="isLoading$ | async">Loading data...</div>
<ul *ngIf="!(isLoading$ | async)">
    <li *ngFor="let d of data">{{ d.value }}</li>
</ul>


// dataview.ts

data: any[] = [];
isLoading$: BehaviorSubject<boolean> = new BehaviorSubject(false);

getData() {

this.isLoading$.next(true);

this._api.getData().subscribe(
        data => {
            this.data = data;
        },
        error => {
            this.error = error;
        },
        complete => {
            this.isLoading$.next(false);
        });
}
Run Code Online (Sandbox Code Playgroud)

  • 为什么它是一个 BehaviourSubject&lt;boolean&gt; 而不仅仅是一个布尔值? (2认同)
  • 请记住,在执行 async 时,它将订阅 Observable。所以在上面的代码中将导致对服务器的两个 api 调用,因为有两个异步管道正在使用。为了防止它,使用异步作为 https://blog.angular-university.io/angular-reactive-templates/ (2认同)

max*_*992 9

我想到了以下几点:

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

export interface WrapObsWithStatus<T> {
  status: ObsStatus;
  value: T;
  error: Error;
}

export function wrapObsWithStatus<T>(obs: Observable<T>): Observable<WrapObsWithStatus<T>> {
  return obs.pipe(
    map(x => ({ status: ObsStatus.SUCCESS, value: x, error: null })),
    startWith({ status: ObsStatus.LOADING, value: null, error: null }),
    catchError((err: Error) => {
      return of({ status: ObsStatus.ERROR, value: null, error: err });
    })
  );
}
Run Code Online (Sandbox Code Playgroud)

然后在您的组件中:

TS

public ObsStatus: typeof ObsStatus = ObsStatus;

public obs$: Observable<WrapObsWithStatus<YOUR_TYPE_HERE>> = wrapObsWithStatus(this.myService.getObs());
Run Code Online (Sandbox Code Playgroud)

的HTML

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

  <div *ngSwitchCase="ObsStatus.ERROR">
    Error! {{ obs.error }}
  </div>

  <div *ngSwitchCase="ObsStatus.LOADING">
    Loading!
  </div>
</div>
Run Code Online (Sandbox Code Playgroud)


tru*_*k18 7

我是通过使用异步管道做到的。但是这种方法仍然需要您手动捕获它以处理错误。有关更多详细信息,请参见此处

应用程序组件.html

<div class="wrapper">
    <div class="form-group" *ngIf="pickupLocations$ | async as pickupLocations; else loading">    
        <ul class="dropdown-menu" *ngIf="pickupLocations.length">
            <li *ngFor="let location of pickupLocations">
                <strong>{{location.Key}}</strong>
            </li>
        </ul>
        <span *ngIf="!pickupLocations.length">There are no locations to display</span>
    </div>

    <ng-template #loading>
        <i class="fa fa-circle-o-notch fa-spin fa-3x fa-fw"></i>
        <span class="sr-only">Loading...</span>
    </ng-template>
</div>
Run Code Online (Sandbox Code Playgroud)

app.component.ts

this.pickupLocations$ = this.apiService.getPickupLocations(storeId);
Run Code Online (Sandbox Code Playgroud)