Angular *ngIf 变量具有异步管道多个条件

问题描述 投票:0回答:7
angular angular-ng-if
7个回答
45
投票

你可以这样做:

<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


31
投票

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

✅✅✅ 保持简单,如果您不需要以用户身份声明

users$ | async
的 $ 隐式值:

<!-- 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 个 Observables,它们有时会疯狂更新,如果我是对的,可能会导致其子级中的长期数据不匹配。


24
投票

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

这对我来说效果很好。

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

或者如果你愿意的话

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

解释

由于 if 表达式的结果被分配给您指定的局部变量,只需以

... && (users$ | async) as users
结束检查即可允许您指定多个条件 并且 指定当所有条件成功时您希望局部变量保存的值。

注意

我最初担心在同一个表达式中使用多个

async
管道可能会创建多个订阅,但经过一些简单的测试(我可能是错的),似乎实际上只进行了一个订阅。


9
投票

这是替代版本,具有更清晰的模板:

<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 上尝试一下。


4
投票
<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>

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

0
投票

从 Angular 18 开始,您可以使用

@let
语法 并简单地编写

@let users = users$ | async;
<div *ngIf="users?.length > 1">
...
</div>
© www.soinside.com 2019 - 2024. All rights reserved.