【问题标题】:Angular *ngIf variable with async pipe multiple conditions具有异步管道多个条件的 Angular *ngIf 变量
【发布时间】:2018-08-24 02:33:26
【问题描述】:

在 Angular 中使用 *ngIf 的文档非常好:https://angular.io/api/common/NgIf 但是,是否有可能有 *ngIf 异步变量并对其进行多次检查? 比如:

<div *ngIf="users$ | async as users && users.length > 1">
...
</div>

当然,也可以使用嵌套的*ngIf,比如:

<div *ngIf="users$ | async as users">
    <ng-container *ngIf="users.length > 1">
    ...
    </ng-container>
</div>

但最好只使用一个容器,而不是两个。

【问题讨论】:

    标签: angular angular-ng-if


    【解决方案1】:

    你可以这样做:

    <ng-template ngFor let-user [ngForOf]="users$ | async" *ngIf="(users$ | async)?.length > 1 && (users$ | async)?.length < 5">
      <div>{{ user | json }}</div>
    </ng-template>
    

    请记住,当使用来自 http 请求的订阅时,这会触发两次请求。所以你应该使用一些状态管理模式或库来避免这种情况发生。

    这是stackblitz

    【讨论】:

    • 是的,这是个好建议,但更复杂的条件呢:
      1 && users.length
      ...
    • 什么样的?你可以有多个这样的语句。在一个 *ngIf 中,只需链接 em。
    • 一般来说,我想保留局部变量以供仅使用一个订阅进一步使用,而您的解决方案没有变量和多个订阅
    • 有人实际测试过这个吗? (我还没有)在我对 Angular 的理解中,你不能在同一个元素上使用多个结构指令。所以 *ngIf 和 *ngFor 通常不能在同一个元素上一起使用!
    • 由于多次使用async,此方案会导致多次从服务器获取数据。
    【解决方案2】:

    我遇到了同样的问题,需要一个 *ngIf + async 变量进行多次检查。

    这对我来说效果很好。

    <div *ngIf="(users$ | async)?.length > 0 && (users$ | async) as users"> ... </div>
    

    或者如果你喜欢

    <div *ngIf="(users$ | async)?.length > 0 && (users$ | async); let users"> ... </div>
    

    说明

    由于 if 表达式的结果已分配给您指定的局部变量,只需以 ... &amp;&amp; (users$ | async) as users 结束检查即可指定多个条件指定您希望局部变量的值当你的所有条件都满足时,保持。

    注意

    我最初担心在同一个表达式中使用多个 async 管道可能会创建多个订阅,但经过一些简单的测试(我可能是错的)之后,似乎实际上只进行了一个订阅。

    【讨论】:

      【解决方案3】:

      我看到每个人都在一个标签中同时使用 *ngFor 和 *ngIf 以及类似的解决方法,但我认为这是一种反模式。在大多数常规编码语言中,您不会在同一行上执行 if 语句和 for 循环,对吗?恕我直言,如果您必须解决问题,因为他们特别不希望您这样做,那么您不应该这样做。 不要实践非“最佳实践”。

      ✅✅✅ 保持简单,如果您不需要将来自 users$ | async 的 $implicit 值声明为用户:

      <!-- readability is your friend -->
      <div *ngIf="(users$ | async).length > 1"> ... </div>
      

      但如果您确实需要声明 as user,请将其包装起来。


      ✅ 用于复杂用例;请注意,生成的标记甚至没有 HTML 标记,这就是 ng-templates 和 ng-containers 的美妙之处!

      @alsami 接受、编辑的答案有效,因为带星号的 *ngFor 是带 ngFor(无星号)的 ng-template 的简写,更不用说双异步管道?。当您将无星号 ngFor 与 *ngIf; 结合使用时,代码确实闻起来不一致。你明白要点了。 *ngIf 具有优先权,那么为什么不将它包装在 ng-container/ng-template 中呢?它不会在生成的标记中使用 HTML 标记来包装您的内部元素。

      <div *ngIf="users$ | async as prods; then thenB; else elseB"></div>
      
      <ng-template #thenB>
        <!-- inner logic -->
        <div *ngIf="prods?.length > 1 && users?.length < 5; else noMatchB">
          Loaded and inbound
        </div>
        <ng-template #noMatchB>Loaded and out of bound</ng-template>
      </ng-template>
      
      <ng-template #elseB>Content to render when condition is false.</ng-template>
      

      ❌不要这样做

      <!-- Big NO NO -->
      <div *ngIf="(users$ | async)?.length > 1 && (users$ | async)?.length < 5"> ... </div>
      

      在您了解管道对生命周期的敏感性之后,它有点令人生畏;他们疯狂地更新。这就是 Angular 没有 SortPipe 和 FilterPipe 的原因。所以,呃,不要这样做;您基本上是在创建 2 个 Observable,它们有时会疯狂更新,如果我是正确的,可能会导致其子项中的长期数据不匹配。

      【讨论】:

      • 如果用例类似于 //这样做是为了避免 false 和 0 1">
      • @Darpan 对于您的情况。你不需要在第一行说othervalue | async !== null。原因是&lt;ng-conatiner *ngIf=" othervalue | asyn &gt;1"&gt; &lt;/ng-conatiner&gt; 由于 JS 的怪异性质,已经检查 null 并检查它是否大于 1;为什么要复杂化两次?
      【解决方案4】:

      这是替代版本,模板更简洁:

      <ng-template [ngIf]="(users$ | async)?.length > 1" [ngIfElse]="noUsersMessage">
        <div *ngFor="let user of (users$ | async)">{{ user | json }}</div>
      </ng-template>
      
      <ng-template #noUsersMessage>No users found</ng-template>
      

      请注意,我们使用users$ | async 2 次。如果您将shareReplay() 运算符添加到user$ Observable,这将起作用:

        public users$: Observable<any[]> = this.someService.getUsers()
          .pipe(shareReplay());
      

      这样,内部模板将能够访问 Observable 的最后一个值并显示结果。

      您可以在stackblitz 上试用。

      【讨论】:

      • 使用共享回放是一种更好的方法。
      • 这应该得到支持。如果我们检查,在同一个 observables 上多次使用异步管道将获得对同一个资源的多个网络调用。在最常见的情况下,应使用 shareReplay 将调用次数减少到 1 个。
      【解决方案5】:
      <div class="mb-5 mt-5 mat-typography text-center">
          <div *ngIf="(applications$ | async) as applications; else noApplication">
            <div *ngIf="applications != null && applications.length > 0; else noApplication">
              show all job applications
            </div>
          </div>
        <ng-template #noApplication>
          <h3>You haven't applied to any jobs. </h3>
        </ng-template>
      </div>
      

      【讨论】:

      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      猜你喜欢
      相关资源
      最近更新 更多
      热门标签