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

时间:2018-03-15 10:16:08

标签: angular angular-ng-if

在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>

但是只使用一个容器而不是两个容器真的很好。

4 个答案:

答案 0 :(得分:4)

简单地这样做

<div *ngfor="let user of users$ | async" *ngIf="(users$ | async)?.length > 1">...</div>

对于“更复杂”的情况,请执行以下操作

<div  *ngfor="let user of users$ | async" *ngIf="(users$ | async)?.length > 1 && (users$ | async)?.length < 5">...</div>

修改:由于您在不使用ng-template的情况下无法使用*ngFor*ngIf,因此以前无效。你可以这样做,例如

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

这是stackblitz

答案 1 :(得分:1)

我遇到了同样的问题,即需要* 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表达式的结果已分配给您指定的本地变量,因此简单地以... && (users$ | async) as users结束检查就可以指定多个条件 并指定希望本地值的值当所有条件都成功时保存的变量。

注意

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

答案 2 :(得分:1)

我看到每个人都在一个标签中使用 * 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,有时会疯狂地更新,如果我正确的话,可能会导致其子项中的长期数据不匹配。

答案 3 :(得分:0)

这是替代版本,带有一些更简洁的模板:

<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$可观察到的位置,那将起作用:

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

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

您可以在stackblitz上尝试一下。