Angular:如何在订阅模板之前通过管道传输 Observable

Angular: How to pipe Observable before subscribing in template

免责声明:这与 问题密切相关。

目前我有两个组件,ParentChildParent 将一个 Observable 传递给 Child,它在模板中订阅了这个 Observable 以避免 lifecycle/memory 泄漏问题。但是我必须 pipe Child 组件中的 Observable 来设置一些东西。

parent.ts:

public $obs = Observable<any>;
....
loadData() {
   this.obs$ = this.myService.getData();
}

parent.html:

<child [data$]="obs$"></child>

child.ts:

@Input() data$ : Observable<any>;

ngOnChanges(changes) {

  if(changes.data$) {
    console.log("changes detected");
    this.data$.pipe(tap(data => console.log("tap worked")));
  }
}

child.html

<div *ngIf="data$ | async as data;">
{{ data || json }}
</div>

数据存在于模板中,控制台日志显示已检测到更改,但从未显示“tap worked”,这让我怀疑我对 pipe 的调用可能也来了晚的。 有什么方法可以在模板“调用”订阅之前进行管道传输吗?

想法是让许多组件与 child 类似,都对数据做不同的事情 object。我考虑过订阅 Parent 中的服务并将 json 值直接传递给所有 child,但这需要我在所有 *ngIf 中写一个 *ngIf =46=]s.

Observable 本质上是惰性的。在您订阅它们之前,它们不会被执行。要查看“点击有效”,您需要订阅它。

this.data$.pipe(tap(data => console.log("tap worked"))).subscribe();

async 默认为您订阅和取消订阅 observable,另外请注意,observable 中的每个订阅者都会获得一个新的执行上下文,并且可以覆盖此行为。

要在订阅晚的情况下缓存结果,您可以在服务中使用 BehaviourSubjectReplaySubject

我建议您不要直接订阅 data$。而是创建另一个您可以阅读的 Observable。

@Input() data$: Observable<any>;
customData$: Observable<any>;

ngOnChanges(changes) {
  if(changes.data$) {
    console.log("changes detected");
    this.customData$ = this.data$.pipe(tap(data => console.log("tap worked")));
  }
}
<div *ngIf="customData$ | async as data;">
  {{ data || json }}
</div>

我认为问题出在您的 ngOnChanges 中。你有条件

  if(changes.data$) {
    console.log("changes detected");
    this.data$.pipe(tap(data => console.log("tap worked")));
  }

这将检查 data$ 的引用是否会更改,但不会检查 data$ 是否发出您真正想要的新值。因此你的点击没有被执行。

相反,你可以

 public data$: Observable<any>;
  @Input() set data(data$: Observable<any>) {
    this.data$ = data$.pipe(tap(x => console.log("tap worked")));
  }