Angular - ngIf 和文本绑定中的异步管道将不会显示第一个发出的值

Angular - Async pipe in ngIf and text binding will not display first emitted value

我有非常简单的组件模板:

<button (click)="emitNextValue()">Next Value</button>

<p *ngIf="text$ | async">
  {{ text$ | async }}
</p>

和组件代码:

export class AppComponent {
  count = 1;
  text$ = new Subject<string>();

  emitNextValue(): void {
    this.text$.next(`Value ${this.count}`);
    this.count += 1;
  }
}

如您所见,仅当 text$ Subjects 发出值时,模板中的 <p> 才会显示。单击“下一个值”按钮将在主题上调用 next,因此应显示该段落。

问题是 <p> 仅在 第二次 单击时显示,我认为这是不正确的。

知道我遗漏了什么,或者这是真正的错误?

演示可在 stackblitz 上获得。

这就是所谓的“晚订户”问题。当传入的 Rx 值在订阅发生之前到达时会出现此问题。

如果您从 html 中删除 *ngIf 指令,它将按预期工作。

<p>
  {{ text$ | async }}
</p>

For More Info

事实是 <p> 元素仅在第一个事件被通知后创建。

因此,在第一个事件被通知后,您在 Dom 中有了元素,因此也在 {{ text$ | async }} 中。然后,当发生第二次点击时,通知第二个事件并触发绑定。

如果将 Subject 替换为 new ReplaySubject<any>(1),您将在第一次点击后显示文本。

原因是 ReplaySubject 将在订阅后立即重播它发出的最后一个值。因此,即使文本绑定发生在通知第一个事件之后,通知的值也会由主题重播,因此显示在 <p> 元素中。

订阅晚了。通常情况下,您可以通过 shareReplay(1) 操作员或使用 ReplaySubject(1) 主题让您的订阅重播最后一个事件。但是在您的特定情况下,有更好的解决方案

<p *ngIf="text$ | async as text">
  {{ text }}
</p>

ngIf 允许“存储”表达式的结果,这对于这种情况非常有用