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>
事实是 <p>
元素仅在第一个事件被通知后创建。
因此,在第一个事件被通知后,您在 Dom 中有了元素,因此也在 {{ text$ | async }}
中。然后,当发生第二次点击时,通知第二个事件并触发绑定。
如果将 Subject
替换为 new ReplaySubject<any>(1)
,您将在第一次点击后显示文本。
原因是 ReplaySubject
将在订阅后立即重播它发出的最后一个值。因此,即使文本绑定发生在通知第一个事件之后,通知的值也会由主题重播,因此显示在 <p>
元素中。
订阅晚了。通常情况下,您可以通过 shareReplay(1)
操作员或使用 ReplaySubject(1)
主题让您的订阅重播最后一个事件。但是在您的特定情况下,有更好的解决方案
<p *ngIf="text$ | async as text">
{{ text }}
</p>
ngIf 允许“存储”表达式的结果,这对于这种情况非常有用
我有非常简单的组件模板:
<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>
事实是 <p>
元素仅在第一个事件被通知后创建。
因此,在第一个事件被通知后,您在 Dom 中有了元素,因此也在 {{ text$ | async }}
中。然后,当发生第二次点击时,通知第二个事件并触发绑定。
如果将 Subject
替换为 new ReplaySubject<any>(1)
,您将在第一次点击后显示文本。
原因是 ReplaySubject
将在订阅后立即重播它发出的最后一个值。因此,即使文本绑定发生在通知第一个事件之后,通知的值也会由主题重播,因此显示在 <p>
元素中。
订阅晚了。通常情况下,您可以通过 shareReplay(1)
操作员或使用 ReplaySubject(1)
主题让您的订阅重播最后一个事件。但是在您的特定情况下,有更好的解决方案
<p *ngIf="text$ | async as text">
{{ text }}
</p>
ngIf 允许“存储”表达式的结果,这对于这种情况非常有用