我为此苦了很长时间。我简化了我公司中的应用程序:
正在工作的堆叠example。
app.component.ts
import { Component } from '@angular/core';
import { Subject } from 'rxjs';
import {map, startWith, takeUntil, tap} from "rxjs/operators";
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
public visible = false;
private dateChangedSubj = new Subject();
public dateChanged$ = this.dateChangedSubj.asObservable();
private state = {
date: "11.02.2019"
};
public date$;
constructor() {
this.date$ = this.dateChanged$.pipe(
startWith(this.state.date),
)
}
show() {
this.visible = true;
}
hide() {
this.visible = false;
}
changeDate() {
this.state.date = "12.02.2019";
this.dateChangedSubj.next(this.state.date);
}
}
app.component.html
<button (click)="show()">Show</button>
<button (click)="hide()">Hide</button>
<button (click)="changeDate()">Change date</button>
<div *ngIf="visible">
<p>This one I can hide: {{ date$ | async }}</p>
</div>
<p>This is always visible: {{date$ | async}}</p>
我将配置存储在一个对象中。在这种情况下,它是state
对象。我在那里存储一个简单的字符串值。我可以通过单击changeDate
按钮来更改此值。然后它将更改对象的值,并通过Subject
发送该新值,因此view
可以被更新。但是,如果在更改发生后显示元素,则该值保持不变。
复制步骤:
changeDate
按钮Show
按钮state
已更新,新显示的值还是旧值答案 0 :(得分:1)
如this article中所述,不建议为同一可观察对象创建多个异步管道。 这是因为每次使用异步管道时,也会创建一个新的订阅。
在下面的代码段中,
<div *ngIf="visible">
<p>This one I can hide: {{ date$ | async }}</p>
</div>
在visible = true
时将创建一个新的订阅。
并且因为您的代码中包含了
this.date$ = this.dateChanged$.pipe(
startWith(this.state.date),
tap(v => console.log('emitted state value', v)), // The previous value
)
它将发出this.state.date
的先前值。
当您再次显示日期时,您还可以看到每次创建新订阅。
这是一个解决方案,可以确保在给定的可观察对象上仅使用一次异步管道。
<ng-container *ngIf="(date$ | async) as date">
<div *ngIf="visible">
<p>This one I can hide: {{ date }}</p>
</div>
<p>This is always visible: {{ date }}</p>
</ng-container>
使用这种方法,只会创建一个订阅。
Here is a StackBlitz example。 另外,请确保检查控制台,以便更好地了解正在发生的事情。(这就是我实际上解决问题的方式)
答案 1 :(得分:0)
您可以使用BehaviorSubject
代替Subject
,并且不需要startWith
。这样,您将拥有最后发出的值,并且它将始终是真实的。
链接到更新的Stackblitz:https://stackblitz.com/edit/angular-h6dk7h