简体   繁体   English

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

[英]Angular *ngIf variable with async pipe multiple conditions

There's quite good doc of using *ngIf in Angular: https://angular.io/api/common/NgIf But, is that possible to have *ngIf async variable and multiple checks on that?在 Angular 中使用 *ngIf 有很好的文档: https ://angular.io/api/common/NgIf 但是,是否可以使用 *ngIf 异步变量并对其进行多次检查? Something like:就像是:

<div *ngIf="users$ | async as users && users.length > 1">
...
</div>

Of course, it's possible to use nested *ngIf, like:当然,也可以使用嵌套的 *ngIf,例如:

<div *ngIf="users$ | async as users">
    <ng-container *ngIf="users.length > 1">
    ...
    </ng-container>
</div>

but it'd be really nice to use only one container, not two.但最好只使用一个容器,而不是两个。

You can do this:你可以这样做:

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

Keep in mind that when using a subscription from a http-request, this would trigger the request twice.请记住,当使用来自 http 请求的订阅时,这将触发请求两次。 So you should use some state-management pattern or library, to not make that happen.因此,您应该使用一些状态管理模式或库来避免这种情况发生。

Here is a stackblitz .这是一个堆栈闪电战

I hit the same issue of needing an *ngIf + async variable with multiple checks.我遇到了同样的问题,需要一个 *ngIf + async 变量进行多次检查。

This ended up working well for me.这对我来说效果很好。

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

or if you prefer或者如果你喜欢

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

Explanation解释

Since the result of the if expression is assigned to the local variable you specify, simply ending your check with ... && (users$ | async) as users allows you to specify multiple conditions and specify what value you want the local variable to hold when all your conditions succeed.由于 if 表达式的结果已分配给您指定的局部变量,因此只需使用... && (users$ | async) as users结束您的检查,您就可以指定多个条件指定您希望局部变量保存的值当你所有的条件都成功时。

Note笔记

I was initially worried that using multiple async pipes in the same expression may create multiple subscriptions, but after some light testing (I could be wrong) it seems like only one subscription is actually made.我最初担心在同一个表达式中使用多个async管道可能会创建多个订阅,但是经过一些简单的测试(我可能是错的)之后,似乎实际上只进行了一个订阅。

I see everyone using *ngFor and *ngIf together in one tag and similar work-arounds, but I think that is an anti-pattern .我看到每个人都在一个标签中同时使用*ngFor 和 *ngIf以及类似的解决方法,但我认为这是一种反模式 In most regular coding languages, you don't do an if statement and a for loop on the same line do you?在大多数常规编码语言中,您不会在同一行上执行 if 语句和 for 循环,对吗? IMHO if you have to work around because they specifically don't want you to, you're not supposed to do that.恕我直言,如果您必须解决问题,因为他们特别不希望您这样做,那么您不应该这样做。 Don't practice what's not "best practice."不要练习不是“最佳实践”的东西。

✅✅✅ Keep it simple, if you don't need to declare the $implicit value from users$ | async ✅✅✅ 保持简单,如果您不需要从users$ | async users$ | async as users:作为用户users$ | async

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

But if you do need to declare as user , wrap it.但是,如果您确实需要声明as user ,请将其包装起来。


✅ For Complex Use Case; ✅ 对于复杂的用例; mind you, the generated markup will not even have an HTML tag, that's the beauty of ng-templates & ng-containers!请注意,生成的标记甚至没有 HTML 标签,这就是 ng-templates 和 ng-containers 的美妙之处!

@alsami's accepted, edited answer works because *ngFor with asterisk is a shorthand for ng-template with ngFor (no asterisk), not to mention the double async pipe 🙏 . @alsami 接受、编辑的答案有效,因为带星号的 *ngFor 是带 ngFor 的 ng-template 的简写(无星号),更不用说双异步管道 🙏 The code really smells of inconsistency when you combine a no-asterisk ngFor with a *ngIf;当您将无星号 ngFor 与 *ngIf; 结合使用时,代码确实闻起来不一致。 you get the gist.你明白要点了。 The *ngIf takes precedence so why not just wrap it in a ng-container/ng-template? *ngIf 具有优先权,那么为什么不将它包装在 ng-container/ng-template 中呢? It won't wrap your inner elements using an HTML tag in the generated markup.它不会在生成的标记中使用 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>

❌ Don't do this ❌ 不要这样做

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

Pipes are a bit daunting after you know about their sensitivity to life cycles;在您了解管道对生命周期的敏感性之后,管道有点令人生畏; they update like mad.他们疯狂地更新。 That's why Angular do NOT have SortPipe nor FilterPipe.这就是 Angular 没有 SortPipe 和 FilterPipe 的原因。 So, erm, don't do this;所以,呃,不要这样做; you're basically creating 2 Observables that sometimes update frantically and may cause long-term data mismatch in its children if I'm correct.您基本上是在创建 2 个 Observable,它们有时会疯狂更新,如果我是正确的,可能会导致其子项中的长期数据不匹配。

Here's the alternative version, with a little bit cleaner template:这是替代版本,模板更简洁:

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

Note that we use users$ | async请注意,我们使用users$ | async users$ | async 2 times. users$ | async 2 次。 That will work if you add shareReplay() operator to user$ Observable:如果您将shareReplay()运算符添加到user$ Observable,这将起作用:

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

That way, inner template will be able to access last value of the Observable and display the results.这样,内部模板将能够访问 Observable 的最后一个值并显示结果。

You can try it out on stackblitz .您可以在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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM