AGGIORNAMENTO: 24/09/16 Angolare 2.0 stabile
Questa domanda ottiene ancora molto traffico, quindi volevo aggiornarla. Con la follia delle modifiche da Alpha, Beta e 7 candidati RC, ho smesso di aggiornare le mie risposte SO fino a quando non sono diventate stabili.
Questo è il caso perfetto per l'utilizzo di Soggetti e ReplaySubjects
Io personalmente preferisco usare ReplaySubject(1)
in quanto consente l'ultimo valore memorizzato per essere passato quando i nuovi abbonati attaccano anche quando in ritardo:
let project = new ReplaySubject(1);
//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result));
http.get('path/to/whatever/projects/1234').subscribe(result => {
//push onto subject
project.next(result));
//add delayed subscription AFTER loaded
setTimeout(()=> project.subscribe(result => console.log('Delayed Stream:', result)), 3000);
});
//Output
//Subscription Streaming: 1234
//*After load and delay*
//Delayed Stream: 1234
Quindi, anche se allego in ritardo o devo caricare più tardi, posso sempre ricevere l'ultima chiamata e non preoccuparmi di perdere la richiamata.
Questo ti consente anche di utilizzare lo stesso flusso per spingere verso il basso su:
project.next(5678);
//output
//Subscription Streaming: 5678
E se sei sicuro al 100%, che devi fare la chiamata una sola volta? Lasciare soggetti aperti e osservabili non va bene ma c'è sempre quel "What If?"
Ecco dove entra in gioco AsyncSubject .
let project = new AsyncSubject();
//subscribe
project.subscribe(result => console.log('Subscription Streaming:', result),
err => console.log(err),
() => console.log('Completed'));
http.get('path/to/whatever/projects/1234').subscribe(result => {
//push onto subject and complete
project.next(result));
project.complete();
//add a subscription even though completed
setTimeout(() => project.subscribe(project => console.log('Delayed Sub:', project)), 2000);
});
//Output
//Subscription Streaming: 1234
//Completed
//*After delay and completed*
//Delayed Sub: 1234
Eccezionale! Anche se abbiamo chiuso l'argomento, ha comunque risposto con l'ultima cosa caricata.
Un'altra cosa è come ci siamo abbonati a quella chiamata http e gestito la risposta. La mappa è ottima per elaborare la risposta.
public call = http.get(whatever).map(res => res.json())
E se avessimo bisogno di annidare quelle chiamate? Sì, potresti usare soggetti con una funzione speciale:
getThing() {
resultSubject = new ReplaySubject(1);
http.get('path').subscribe(result1 => {
http.get('other/path/' + result1).get.subscribe(response2 => {
http.get('another/' + response2).subscribe(res3 => resultSubject.next(res3))
})
})
return resultSubject;
}
var myThing = getThing();
Ma è molto e significa che hai bisogno di una funzione per farlo. Inserisci FlatMap :
var myThing = http.get('path').flatMap(result1 =>
http.get('other/' + result1).flatMap(response2 =>
http.get('another/' + response2)));
Dolce, var
è un osservabile che ottiene i dati dall'ultima chiamata http.
OK va benissimo ma voglio un servizio angular2!
Ti ho preso:
import { Injectable } from '@angular/core';
import { Http, Response } from '@angular/http';
import { ReplaySubject } from 'rxjs';
@Injectable()
export class ProjectService {
public activeProject:ReplaySubject<any> = new ReplaySubject(1);
constructor(private http: Http) {}
//load the project
public load(projectId) {
console.log('Loading Project:' + projectId, Date.now());
this.http.get('/projects/' + projectId).subscribe(res => this.activeProject.next(res));
return this.activeProject;
}
}
//component
@Component({
selector: 'nav',
template: `<div>{{project?.name}}<a (click)="load('1234')">Load 1234</a></div>`
})
export class navComponent implements OnInit {
public project:any;
constructor(private projectService:ProjectService) {}
ngOnInit() {
this.projectService.activeProject.subscribe(active => this.project = active);
}
public load(projectId:string) {
this.projectService.load(projectId);
}
}
Sono un grande fan di osservatori e osservabili, quindi spero che questo aggiornamento aiuti!
Risposta originale
Penso che questo sia un caso d'uso di utilizzo di un Soggetto Observable o Angular2
la EventEmitter
.
Nel tuo servizio crei un oggetto EventEmitter
che ti consente di spingere i valori su di esso. In Alpha 45 devi convertirlo con toRx()
, ma so che stavano lavorando per sbarazzarsene, quindi in Alpha 46 potresti essere in grado di restituire semplicemente il file EvenEmitter
.
class EventService {
_emitter: EventEmitter = new EventEmitter();
rxEmitter: any;
constructor() {
this.rxEmitter = this._emitter.toRx();
}
doSomething(data){
this.rxEmitter.next(data);
}
}
In questo modo c'è il singolo su EventEmitter
cui le diverse funzioni di servizio possono ora spingere.
Se volessi restituire un osservabile direttamente da una chiamata, potresti fare qualcosa del genere:
myHttpCall(path) {
return Observable.create(observer => {
http.get(path).map(res => res.json()).subscribe((result) => {
//do something with result.
var newResultArray = mySpecialArrayFunction(result);
observer.next(newResultArray);
//call complete if you want to close this stream (like a promise)
observer.complete();
});
});
}
Ciò ti consentirebbe di farlo nel componente:
peopleService.myHttpCall('path').subscribe(people => this.people = people);
E scherza con i risultati della chiamata nel tuo servizio.
Mi piace creare il EventEmitter
flusso da solo nel caso avessi bisogno di accedervi da altri componenti, ma potrei vedere entrambi i modi di lavorare ...
Ecco un plunker che mostra un servizio di base con un emettitore di eventi: Plunkr