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 Angular2la EventEmitter.
Nel tuo servizio crei un oggetto EventEmitterche 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 EventEmittercui 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 EventEmitterflusso 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