2016-05-31 5 views
5

Ich bin relativ neu zu angular2 und ich bin irgendwie auf etwas fest.Angular2 globale Variable beobachtbar

Ich habe einen globalen settings.service erstellt. Dieser Dienst ruft Einstellungen von einer API ab und füllt das Einstellungsmodell mit den gesammelten Daten.

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

Dies funktioniert gut und die Einstellungen korrekt eingestellt sind, wenn ich die Rückgabedaten in der .map testen

Aber wenn ich versuche GetSettings von der Komponente zu nennen, wo ich Diese Daten werden leer zurückgegeben. Der Dienst ist im Bootstrap definiert.

Muss ich die Variable 'Einstellungen' beobachtbar machen? Jede Hilfe würde sehr geschätzt werden!

Tnx!

+0

Scheint, dass Ihr tatsächlicher Code anders ist. 'korrekt gesetzt, wenn ich die Rückgabedaten in der .map' teste. Dieser Code 'this.http.get ('/ settings') .map (response => { this.settings = response.json() });' wird nie ohne 'subscribe (...)' –

+0

ausgeführt Ja, mein eigentlicher Code ist anders;) Aber um der Frage willen habe ich den Code vereinfacht. Ich werde das Codebeispiel aktualisieren;) – Jeffrey

Antwort

2

Ich würde Caching in Ihren Dienst implementieren mit dem do Betreiber:

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

Wenn Sie ein BehaviorSubject verwenden, müssen Sie nicht 'share()' oder cache. Sehen Sie meine Antwort, wenn Sie interessiert sind. –

0

warum nicht Sie Ihren Dienst wie folgt verwenden: -

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

und als verwenden .subscribe() Methode, wo Sie erhalten möchten die Daten und zeigen auf der Ansicht

+0

Ich hatte es so, aber ich versuche, die Menge der API-Aufrufe zu reduzieren. Da sich die Daten niemals ändern oder nur vom Client selbst geändert werden, muss nicht jedes Mal nach neuen Daten gesucht werden. – Jeffrey

+0

okay, als Sie @thierry in seiner Antwort vorgeschlagen verwenden können mit 'beobachtbar' –

7

Verwenden Sie eine BehaviorSubject in Ihrem Service. Es ist bereits geteilt, und es werden neue Teilnehmer den aktuellen Wert geben (so tut es das Caching für Sie):

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

Dann die beobachtbare in Ihrer Vorlage verwenden, um mit dem asyncPipe oder extrahieren die Daten in ein Komponente Variable:

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

Plunker

im Plunker ich eine untergeordnete Komponente haben, die 4 Sekunden wartet und dann subscribe() s, um anzuzeigen, dass der letzte/aktuelle Wert tatsächlich abgerufen wird. Der Plunker demonstriert auch die Verwendung der asyncPipe.

+0

Während ich die Idee der Verwendung eines BehaviorSubject für globale Daten, habe ich Schwierigkeiten, mit seinem ursprünglichen Wert, der emittiert wird, bevor irgendwelche realen Daten abgerufen worden ist . In meinem Fall muss ich zusätzliche Daten in einer Komponente basierend auf dem Wert des BehaviorSubject abrufen, das fehlschlägt, wenn es einen Nullwert enthält. Irgendwelche Ideen, wie man das löst? – Liquinaut

+0

Mein Problem wurde gelöst. Für jeden, der nach einer Lösung sucht, können Sie ein ReplaySubject anstelle eines BehaviorSubject verwenden, um einen Subject zu erhalten, der Änderungen ausgibt, ohne einen Anfangswert zu haben. Das ReplaySubject gibt keine Daten aus, bis next() das erste Mal aufgerufen wird. – Liquinaut

+0

@Mark Rajcok - warum wartest du 4 Sekunden? Wie man auf seinen Anfangswert wartet? –