Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular2 global variable observable

I'm fairly new to angular2 and I'm kinda stuck on something.

I've created a global settings.service. This service fetches settings from an API and populate the settings model with the collected data.

The service:

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;
}

This works fine and the settings are correctly set when I test the return data in the .map

But when I try to call GetSettings from the component where I need this data, it returns empty. The service is defined in the bootstrap.

Do I need to make the 'settings' variable observable? Any help would be highly appreciated!

Tnx!

like image 528
Jeffrey Avatar asked May 31 '16 10:05

Jeffrey


2 Answers

Use a BehaviorSubject in your service. It is already shared, and it will give new subscribers the current value (so it does the caching for you):

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())
      });
  }
}

Then use the observable in your template with the asyncPipe, or extract the data into a component variable:

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

Plunker

In the Plunker I have a child component that waits 4 seconds and then subscribe()s, to show that the latest/current value is indeed retrieved. The Plunker also demonstrates use of the asyncPipe.

like image 136
Mark Rajcok Avatar answered Sep 29 '22 02:09

Mark Rajcok


I would implement caching into your service using the do operator:

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;
  }
}
like image 31
Thierry Templier Avatar answered Sep 29 '22 02:09

Thierry Templier