你可以这样做:
<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。
我看到每个人都在一个标签和类似的解决方法中一起使用 *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,它们有时会疯狂更新,如果我是对的,可能会导致其子级中的长期数据不匹配。
我遇到了同样的问题,需要一个 *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
管道可能会创建多个订阅,但经过一些简单的测试(我可能是错的),似乎实际上只进行了一个订阅。
这是替代版本,具有更清晰的模板:
<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 上尝试一下。
<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>
<div *ngIf="(users$ | async)?.length" >
.....
.....
.....
.....
</div>