使用异步管道解析 Angular 模板中的自定义 rxjs 主题

Resolve custom rxjs Subject in Angular template using async pipe

我的 Angular 应用程序中有一个自定义的 BehaviourSubject,它在我的模板中用作 Observable。

当我在主题上调用 next 时,我希望模板中的主题得到解析。我使用 async 管道来监听此 Subject 中的异步更改。

我在 Stackblitz 中创建了一个示例来说明我遇到的问题:https://stackblitz.com/edit/angular-kmou5e

app.component.ts 中,我创建了一个示例异步方法,它在超时后将值设置为 this.data。一旦设置了 this.datahello.component.ts 就会被初始化和渲染。我在 HelloComponent 中收听 OnChanges 并在 HelloComponent.

中对自定义主题调用 next()

正如您在 HelloComponent 的模板中看到的那样,我希望观察到的主题 customSubject$ 在通过 [=18= 获得值后立即呈现为 <h1> ].

您可以看到,调用了 customSubject$ 的订阅,如日志中所示。只有模板不呈现此 Observable/Subject.

如何在使用自定义 Subject 时让模板呈现?我需要使用不同的管道吗?

仅供参考:我还尝试使用 combineLatest 将 Subject 的值分配给新的 Observable,但效果不佳。

这是时间问题。只需将您的主题更改为行为主题(缓存最后发出的值),您的模板就会显示最新发出的值。

这里是good resource关于各种主题的。

很好的问题。问题是 lifecycle hooks Subject 的顺序没有值,如果运气不好,它只会向订阅者进行多播。现在生命周期按此顺序运行。构造函数、ngOnChanges、OnNgInit ..... 然后加载视图和子组件。所以为了让你看到这个值,你需要使用 BehaviorSubject 来缓冲它。

看看我在说什么

import { Component, Input, OnChanges, SimpleChanges } from '@angular/core';
import { combineLatest, Observable, Subject } from 'rxjs';

@Component({
  selector: 'hello',
  template: `<h1>{{ customSubject$ | async }}</h1>
             <h2>{{test}}</h2>
  `
})
export class HelloComponent implements OnChanges  {
  @Input() name: string;
public customSubject$: Subject<string>;

    public test ='Before ngOnChanges run';

  constructor() {
      console.log('constructed');

    this.customSubject$ = new Subject();
    this.customSubject$.subscribe(s => {
      console.log('customSubject$ subscription resolved with ' + s);
    });
  }

  ngOnChanges(changes: SimpleChanges) {
    if (changes.hasOwnProperty('name')) {
      console.log('ngOnChanges is called with ' + this.name);
      this.customSubject$.next(this.name);

    }
          this.test ='After ngOnChanges Ran';
  }
}

您有一个测试变量,其值已在 ngOnChanges 中更改。您永远看不到值 'Before ngOnChanges run',因为视图尚未初始化。

现在您的 *ngIf='data' 让您更加困惑,因为组件不是在 ngIf 解析为 true 之前构造的

它有助于增加你看到这个的延迟

  ngOnInit() {
    setTimeout(() => {
      this.data = 'some string';
    }, 5000);
  }