2016-05-31 68 views
5

Sono abbastanza nuovo per Angular2 e sono piuttosto bloccato su qualcosa.Variabile globale Angular2 osservabile

Ho creato un settings.service globale. Questo servizio recupera le impostazioni da un'API e popola il modello delle impostazioni con i dati raccolti.

Il servizio:

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

Questo funziona bene e le impostazioni vengono correttamente impostato quando prova i dati di ritorno nel .map

Ma quando provo a chiamare getsettings dal componente in cui ho bisogno questi dati, restituisce vuoto. Il servizio è definito nel bootstrap.

Devo rendere visibile la variabile 'impostazioni'? Qualsiasi aiuto sarebbe molto apprezzato!

Tnx!

+0

Sembra che il tuo codice attuale sia diverso. 'impostato correttamente quando eseguo il test dei dati di ritorno in .map'. Questo codice 'this.http.get ('/ settings') .map (response => { this.settings = response.json() });' non viene mai eseguito senza 'subscribe (...)' –

+0

Sì, il mio codice attuale è diverso;) Ma nell'interesse della domanda ho semplificato il codice. Aggiornerò l'esempio di codice;) – Jeffrey

risposta

2

avrei implementare la cache nel vostro servizio utilizzando il do dell'operatore:

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

Se si utilizza BehaviorSubject, non sarà necessario 'share()' o cache. Vedi la mia risposta se interessato. –

0

perché non si utilizza il servizio come questo: -

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

e di utilizzare .subscribe() metodo in cui si desidera ottenere i dati e mostra sulla vista

+0

Ho avuto questo, ma sto cercando di ridurre la quantità di chiamate API. Poiché i dati non cambiano mai o vengono modificati solo dal client stesso, non è necessario chiamare ogni volta "nuovi" dati. – Jeffrey

+0

okay che puoi usare come @thierry suggerito nella sua risposta usando 'osservabile' –

7

Utilizzare un BehaviorSubject nel vostro servizio. Si è già condivisa, e darà nuovi abbonati il ​​valore corrente (in modo che fa il caching per voi):

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

quindi utilizzare il osservabile nel modello con l'asyncPipe, oppure estrarre i dati in un componente variabile:

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

Plunker

Nel Plunker ho un componente figlio che attende 4 secondi e poi subscribe() s, per mostrare che il valore più recente/corrente è effettivamente recuperato. Il Plunker dimostra anche l'uso di asyncPipe.

+0

Mentre mi piace l'idea di usare BehaviorSubject per i dati globali, ho difficoltà a gestire il suo valore iniziale che viene emesso prima che i dati reali siano stati recuperati . Nel mio caso ho bisogno di ottenere dati aggiuntivi in ​​un componente basato sul valore di BehaviorSubject, che fallisce se contiene un valore nullo. Qualche idea di come si possa risolvere? – Liquinaut

+0

Risolto il mio problema. Per chiunque cerchi una soluzione, è possibile utilizzare un oggetto ReplaySubject anziché BehaviorSubject per ottenere un oggetto che emette le modifiche senza avere un valore iniziale. ReplaySubject non emetterà alcun dato fino a quando next() non viene chiamato per la prima volta. – Liquinaut

+0

@ Mark Rajcok - perché aspetti 4 secondi? Come aspettare il suo valore iniziale? –