【问题标题】:Angular Component Observable binding timeAngular Component Observable 绑定时间
【发布时间】:2019-07-24 13:38:52
【问题描述】:

我在其他地方看到过与此类似的问题,但没有答案 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' });
  }
}

然后在组件中,我将上面的 observable 直接分配给模型上的一个属性,并使用 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,即使在我第一次单击按钮(将值放入本地存储)并重新加载页面(您可以看到 Tom 被设置为控制台中的下一个值)。

单击按钮虽然会提供另一个“下一个”值,但 UI 会正确更新。看到这一切,似乎在将第一个值传递给主题之后订阅了 observable,因此 UI 没有获得该初始值。我尝试了许多不同的事情都无济于事。我尝试使用 BehaviorSubject 代替。还尝试使用shareReplay 和其他运算符。我还尝试在 ngAfterViewInit 方法中设置 observable。仍然没有运气。如果数据在本地存储中,我认为用户不应该立即执行某些操作来查看它,但我似乎找不到让它工作的正确方法。

如何正确设置此 observable,以便它从本地存储中获取信息并将其放入视图中,而无需用户采取任何操作?

这是带有代码的StackBlitz

【问题讨论】:

标签: angular rxjs observable


【解决方案1】:

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

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

【讨论】:

  • 对于 StackBlitz 示例,这似乎可行,因此我将其标记为答案。我正在尝试在 Chrome 扩展程序中使用它,无论我尝试什么,SubjectBehaviorSubjectReplaySubject,它仍然无法正常工作。有什么想法吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-07-19
  • 2017-10-12
  • 1970-01-01
  • 2017-11-20
  • 2016-08-16
  • 2018-09-29
相关资源
最近更新 更多