角组件可观察的绑定时间

时间:2019-07-24 13:38:52

标签: angular rxjs observable

我在其他地方也看到过类似的问题,但没有答案1

我有一项正在寻找本地存储值的服务。如果存在,则将其设置为Subject上的下一个值,否则它将进行http调用。

我知道下面是一个人为的例子,但是我试图提出一个MVP。

test.service.ts

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs/internal/Subject';

@Injectable({ providedIn: 'root' })
export class TestService {
  private testSubject: Subject<{ name: string }> = new Subject();
  testObservable$ = this.testSubject.asObservable();

  constructor() {
    var cat = localStorage.getItem('myCat');
    console.log(cat);
    this.testSubject.next({ name: cat });
  }

  update() {
    localStorage.setItem('myCat', 'Tom');
    this.testSubject.next({ name: 'not Tom' });
  }
}

然后在组件中,我直接从上方将可观察对象分配给模型上的属性,并使用async管道将其公开给模板。

app.component.ts

import { Component, ChangeDetectionStrategy } from '@angular/core';
import { TestService } from './test.service';
import { map } from 'rxjs/internal/operators/map';

@Component({
  selector: 'my-app',
  template: `
  <p>
    Hello {{test$ | async}}!
  </p>

  <button (click)="onClick()">Click me!</button>`,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class AppComponent {
  test$ = this.testService
              .testObservable$
              .pipe(
                map(a => a.name)
              );

  constructor(private testService: TestService) {
  }

  onClick() {
    this.testService.update();
  }
}

渲染视图时,即使我第一次单击按钮(将值存储在本地存储中)并重新加载页面(您可以看到Tom设置为控制台中的下一个值)。

尽管单击按钮会提供另一个“下一个”值,然后UI确实会正确更新。看到所有这些,似乎在将第一个值传递给主题之后,就好像已在观察该对象,因此UI并没有获得该初始值。我尝试了许多不同的尝试,但都无济于事。我尝试使用BehaviorSubject代替。还尝试使用shareReplay和其他运算符。我也尝试过在ngAfterViewInit方法中设置可观察对象。仍然没有运气。如果数据在本地存储中,我认为用户不必采取任何措施即可立即查看它,但是我似乎找不到找到使它正常工作的正确方法。

如何正确设置此可观察对象,以便它可以从本地存储中获取信息并将其放入视图中而无需用户采取任何措施?

这里是带有代码的StackBlitz

1 个答案:

答案 0 :(得分:0)

这是一个标准的订阅时间问题...信号发出后,异步管道正在订阅...使其成为一个行为主题或重播主题,而不是将最后一个主题值广播给新订阅者。

private testSubject: ReplaySubject<{ name: string }> = new ReplaySubject(1);