【问题标题】:Angular2 global variable observableAngular2全局变量可观察
【发布时间】:2016-09-29 07:37:36
【问题描述】:

我对 angular2 还很陌生,我有点卡住了。

我创建了一个全局 settings.service。此服务从 API 获取设置并使用收集的数据填充设置模型。

服务:

public settings : settingsModel;

constructor(public http: Http){ 
     this.setSettings()
         .subscribe(
             (data) => {
                  this.settings = data
             });
  }

setSettings() : Observable<any>{
   return : this.http.get('/settings')
            .map(response =>  response.json());
}

getSettings(){
     return this.settings;
}

当我在 .map 中测试返回数据时,这工作正常并且设置正确

但是当我尝试从需要此数据的组件中调用 GetSettings 时,它返回空。该服务在引导程序中定义。

我需要使“设置”变量可观察吗?任何帮助将不胜感激!

Tnx!

【问题讨论】:

  • 您的实际代码似乎不同。 correctly set when I test the return data in the .map。没有subscribe(...),这段代码this.http.get('/settings') .map(response =&gt; { this.settings = response.json() });永远不会被执行
  • 是的,我的实际代码是不同的;)但是为了这个问题,我简化了代码。我将更新代码示例;)

标签: angular observable


【解决方案1】:

在您的服务中使用BehaviorSubject。它已经被共享了,它将为新订阅者提供当前值(因此它会为您进行缓存):

import {Injectable}      from '@angular/core';
import {Http}            from '@angular/http';
import {BehaviorSubject} from 'rxjs/BehaviorSubject';
import {settingsModel}   from 'settingsModel';

@Injectable()
export class MyService {
  private _settingsSource = new BehaviorSubject<settingsModel>(null);
  settings$ = this._settingsSource.asObservable();
  constructor(private _http:Http) {
    this._http.get('./settings.json')
      .subscribe(response => {
        //console.log('response', response)
        this._settingsSource.next(response.json())
      });
  }
}

然后将模板中的 observable 与 asyncPipe 一起使用,或者将数据提取到组件变量中:

this.settings$ = this._myService.settings$;  // use with asyncPipe
this._myService.settings$.subscribe(data => this.settings = data);

Plunker

在 Plunker 中,我有一个等待 4 秒然后 subscribe()s 的子组件,以表明确实检索到了最新/当前值。 Plunker 还演示了 asyncPipe 的使用。

【讨论】:

  • 虽然我喜欢将 BehaviorSubject 用于全局数据的想法,但我很难处理在获取任何真实数据之前发出的初始值。在我的情况下,我需要根据 BehaviorSubject 的值在组件中获取其他数据,如果它包含空值,则会失败。任何想法如何解决这个问题?
  • 解决了我的问题。对于任何寻求解决方案的人,您可以使用 ReplaySubject 而不是 BehaviorSubject 来获取发出更改而没有初始值的 Subject。在第一次调用 next() 之前,ReplaySubject 不会发出任何数据。
  • @Mark Rajcok - 为什么要等 4 秒?如何等待他的初始值?
  • @Tudor-RaduBarbu,我等了 4 秒钟,只是为了展示稍后订阅的任何组件将如何获得 observable 的最新/当前值。
  • @MarkRajcok,谢谢伙计,但你能告诉我吗?完成操作后如何取消/重置对象“this.settings$”。
【解决方案2】:

我会使用 do 运算符在您的服务中实现缓存:

private settings : settingsModel;

constructor(public http: Http){ 
  this.settingsObservable = this.http.get('/settings')
        .map(response => response.json())
        .do(settings => {
          this.settings = settings;
        }).share();
}

getSettings() {
  if (this.settings) {
    return Observable.of(this.settings);
  } else {
    return this.settingsObservable;
  }
}

【讨论】:

  • 如果您使用 BehaviorSubject,您将不必 share() 或缓存。有兴趣可以看我的回答。
【解决方案3】:

你为什么不这样使用你的服务:-

  public settings : settingsModel;

constructor(public http: Http){ }

GetSettings(){
  return this.http.get('/settings')
     .map(response => {
           this.settings = response.json()   // here setting your data to `this.setting` 
           return this.settings;
      })
      .catch(err => {
           console.log(err)  // handle your error as you want to handle
      })
}

而不是使用.subscribe() 方法来获取数据并显示在视图上

【讨论】:

  • 我就是这样,但我正在尝试减少 API 调用的数量。由于数据从不更改,或者仅由客户端本身更改,因此不需要每次都调用“新”数据。
  • 好吧,就像@thierry 在他的回答中建议的那样使用observable
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-16
  • 2014-10-10
  • 1970-01-01
  • 2021-01-26
  • 2015-07-03
相关资源
最近更新 更多