Angular *ngIf 变量与异步管道多个条件
Angular *ngIf variable with async pipe multiple conditions
在 Angular 中有关于使用 *ngIf 的很好的文档:https://angular.io/api/common/NgIf
但是,是否可以使用 *ngIf async 变量并对其进行多次检查?
类似于:
<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>
但如果只使用一个容器,而不是两个,那就太好了。
你可以这样做:
<ng-template ngFor let-user [ngForOf]="users$ | async" *ngIf="(users$ | async)?.length > 1 && (users$ | async)?.length < 5">
<div>{{ user | json }}</div>
</ng-template>
请记住,当使用来自 http-request 的订阅时,这会触发请求两次。因此,您应该使用一些 state-management 模式或库,以免发生这种情况。
这里是stackblitz.
我遇到了同样的问题,需要一个 *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
管道可能会创建多个订阅,但经过一些简单的测试(我可能是错的)似乎实际上只进行了一个订阅。
这是替代版本,模板更简洁:
<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 上试用。
我看到每个人都在一个标签中一起使用 *ngFor 和 *ngIf 以及类似的解决方法,但我认为这是一种反模式。在大多数常规编码语言中,您不会在同一行上执行 if 语句和 for 循环,对吗?恕我直言,如果您因为他们特别不希望您这样做而不得不变通,那么您不应该那样做。 不练不练"best practice."
✅✅✅ 保持简单,如果您不需要声明来自 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 的 shorthand,更不用说双异步管道 .当您将无星号 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,它们有时会疯狂更新,如果我是正确的话,可能会导致其子项的长期数据不匹配。
<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>
在 Angular 中有关于使用 *ngIf 的很好的文档:https://angular.io/api/common/NgIf 但是,是否可以使用 *ngIf async 变量并对其进行多次检查? 类似于:
<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>
但如果只使用一个容器,而不是两个,那就太好了。
你可以这样做:
<ng-template ngFor let-user [ngForOf]="users$ | async" *ngIf="(users$ | async)?.length > 1 && (users$ | async)?.length < 5">
<div>{{ user | json }}</div>
</ng-template>
请记住,当使用来自 http-request 的订阅时,这会触发请求两次。因此,您应该使用一些 state-management 模式或库,以免发生这种情况。
这里是stackblitz.
我遇到了同样的问题,需要一个 *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
管道可能会创建多个订阅,但经过一些简单的测试(我可能是错的)似乎实际上只进行了一个订阅。
这是替代版本,模板更简洁:
<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 上试用。
我看到每个人都在一个标签中一起使用 *ngFor 和 *ngIf 以及类似的解决方法,但我认为这是一种反模式。在大多数常规编码语言中,您不会在同一行上执行 if 语句和 for 循环,对吗?恕我直言,如果您因为他们特别不希望您这样做而不得不变通,那么您不应该那样做。 不练不练"best practice."
✅✅✅ 保持简单,如果您不需要声明来自 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 的 shorthand,更不用说双异步管道 .当您将无星号 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,它们有时会疯狂更新,如果我是正确的话,可能会导致其子项的长期数据不匹配。
<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>