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

Vit*_*aly 9 angular-ng-if angular

有一个在Angular中使用* ngIf的很好的文档:https ://angular.io/api/common/NgIf 但是,是否可以使用* ngIf异步变量并对此进行多次检查?就像是:

<div *ngIf="users$ | async as users && users.length > 1">
...
</div>
Run Code Online (Sandbox Code Playgroud)

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

<div *ngIf="users$ | async as users">
    <ng-container *ngIf="users.length > 1">
    ...
    </ng-container>
</div>
Run Code Online (Sandbox Code Playgroud)

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

Kee*_*ego 22

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

这最终对我来说效果很好。

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

或者如果你喜欢

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

解释

由于 if 表达式的结果已分配给您指定的局部变量,因此简单地结束检查... && (users$ | async) as users允许您指定多个条件指定当所有条件都成功时您希望局部变量保持什么值。

笔记

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


小智 6

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

???保持简单,如果您不需要从users$ | async用户中声明 $implicit 值:

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

但是,如果您确实需要声明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>
Run Code Online (Sandbox Code Playgroud)

? 不要这样做

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

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


als*_*ami 5

像这样简单地做

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

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

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

编辑:上是行不通的,因为你不能使用*ngFor*ngIf不使用NG-模板。例如,您会那样做

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

这是一堆堆炸弹

  • 有人实际测试过吗?(我没有,但是)在我对Angular的理解中,不能在同一个元素上使用多个结构指令。因此* ngIf和* ngFor通常不能在同一元素上一起使用! (3认同)

im.*_*tov 5

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

<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>
Run Code Online (Sandbox Code Playgroud)

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

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

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

你可以在stackblitz试一试