首页 > 解决方案 > 为什么在使用带有 *ngIf 内容切换的异步管道时,Ionic (Angular) 中的可观察对象会发送新的服务请求?

问题描述

我正在创建一个屏幕,该屏幕使用段组件来过滤使用来自 http 请求的异步管道的 observable 列表中的结果。我将为此创建一个管道过滤器来清理它,因为它是多余的,但我更担心它为什么会这样发生——我是 observables 的新手。一切都按预期显示和工作,但是当我切换屏幕顶部的段过滤器时,它每次都会向 api 发送一个新请求,并根据客户类型重建列表。是因为 *ngIf 是基于客户的 type 属性吗?每次切换时发送一个新请求似乎有点荒谬。此外,如果您可以建议使用过滤器(或任何方法)更好的方法来做到这一点,我们将不胜感激。

我的服务类中的方法:

 /**
 * Get a list of the user's customers
 */
list(): Observable<Customer[]> {
    return this.authHttp.get<Customer[]>('/api/customers')
        .map(customers => {
            return customers.json().data
        }).pipe(
            catchError(this.handleError('getCustomers', []))
        );
}

我的控制器中的方法:

ionViewDidLoad() {
    this.customers = this.customerService.list();
}

具有模型绑定的分段组件:

<ion-segment [(ngModel)]="type">
  <ion-segment-button value="prospect">
    Prospects
  </ion-segment-button>
  <ion-segment-button value="customer">
    Customers
  </ion-segment-button>
</ion-segment>

内容切换和异步管道:

<div [ngSwitch]="type">
  <ion-list *ngSwitchCase="'prospect'">
    <ng-container *ngFor="let customer of customers | async">
      <button *ngIf="customer.type==='prospect'" ion-item (click)="customerSelected(customer)">
        {{ customer.first_name }} {{ customer.last_name }}
      </button>
    </ng-container>
  </ion-list>
  <ion-list *ngSwitchCase="'customer'">
    <ng-container *ngFor="let customer of customers | async">
      <button ion-item *ngIf="customer.type==='customer'" (click)="customerSelected(customer)">
        {{ customer.first_name }} {{ customer.last_name }}
      </button>
    </ng-container>
  </ion-list>
</div>

标签: angularionic-frameworkrxjsobservablereactive-programming

解决方案


因为 NgSwitch 正在删除 dom 元素。因此,当您切换开关并将异步管道添加到 dom 时,它会在您的 observable 上调用 .subscribe() ,这意味着它将重新调用您的 API。

来自 Angular 文档: https ://angular.io/api/common/NgSwitch#ngSwitch

NgSwitch

匹配 switch 表达式。当嵌套匹配表达式时添加/删除 DOM 子树

您可以设置结果而不是直接绑定到 observable。

ionViewDidLoad() {
    this.customerService.list().subscribe(customers => {
        this.customers = customers;
    });
}

然后从 *ngFor 中删除异步管道。

<ng-container *ngFor="let customer of customers">

或者不使用 ngSwitch,使用 [hidden] 属性。

  <ion-list [hidden]="type !== 'prospect'">
    <ng-container *ngFor="let customer of customers | async">
      <button *ngIf="customer.type==='prospect'" ion-item (click)="customerSelected(customer)">
        {{ customer.first_name }} {{ customer.last_name }}
      </button>
    </ng-container>
  </ion-list>
  <ion-list [hidden]="type !== 'customer'">
    <ng-container *ngFor="let customer of customers | async">
      <button ion-item *ngIf="customer.type==='customer'" (click)="customerSelected(customer)">
        {{ customer.first_name }} {{ customer.last_name }}
      </button>
    </ng-container>
  </ion-list>

[隐藏] 虽然有一些警告......

Angular 中 ngShow 和 ngHide 的等价物是什么?


推荐阅读