UPDATE: 9/24/16 Angular 2.0 Stable
Pertanyaan ini masih mendapatkan banyak lalu lintas, jadi, saya ingin memperbaruinya. Dengan kegilaan perubahan dari kandidat Alpha, Beta, dan 7 RC, saya berhenti memperbarui jawaban SO saya sampai mereka menjadi stabil.
Ini adalah kasus yang sempurna untuk menggunakan Subjek dan ReplaySubyek
Saya pribadi lebih suka menggunakan ReplaySubject(1)
karena memungkinkan nilai terakhir yang disimpan diteruskan ketika pelanggan baru melampirkan bahkan ketika terlambat:
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
Jadi, bahkan jika saya melampirkan terlambat atau perlu memuat nanti saya selalu bisa mendapatkan panggilan terbaru dan tidak khawatir kehilangan callback.
Ini juga memungkinkan Anda menggunakan aliran yang sama untuk mendorong ke:
project.next(5678);
//output
//Subscription Streaming: 5678
Tetapi bagaimana jika Anda yakin 100%, bahwa Anda hanya perlu melakukan panggilan sekali saja? Meninggalkan subjek terbuka dan dapat diobservasi tidak baik tetapi selalu ada "Bagaimana Jika?"
Di situlah AsyncSubject masuk.
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
Luar biasa! Meskipun kami menutup subjek, tetap menjawab dengan hal terakhir yang dimuat.
Hal lain adalah bagaimana kami berlangganan panggilan http itu dan menangani responsnya. Peta bagus untuk memproses respons.
public call = http.get(whatever).map(res => res.json())
Tetapi bagaimana jika kita perlu membuat sarang panggilan itu? Ya, Anda dapat menggunakan subjek dengan fungsi khusus:
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();
Tapi itu banyak dan berarti Anda perlu fungsi untuk melakukannya. Masukkan FlatMap :
var myThing = http.get('path').flatMap(result1 =>
http.get('other/' + result1).flatMap(response2 =>
http.get('another/' + response2)));
Manis, var
ini bisa diamati yang mendapatkan data dari panggilan http akhir.
OK itu bagus tapi saya ingin layanan angular2!
Aku mendapatkanmu:
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);
}
}
Saya penggemar berat pengamat dan pengamat jadi saya harap pembaruan ini membantu!
Jawaban Asli
Saya rasa ini adalah kasus penggunaan menggunakan Subjek diamati atau Angular2
yang EventEmitter
.
Dalam layanan Anda, Anda membuat EventEmitter
yang memungkinkan Anda untuk mendorong nilai ke dalamnya. Di Alpha 45 Anda harus mengonversinya dengan toRx()
, tetapi saya tahu mereka sedang berusaha untuk menghilangkannya, jadi di Alpha 46 Anda mungkin dapat mengembalikannya EvenEmitter
.
class EventService {
_emitter: EventEmitter = new EventEmitter();
rxEmitter: any;
constructor() {
this.rxEmitter = this._emitter.toRx();
}
doSomething(data){
this.rxEmitter.next(data);
}
}
Cara ini memiliki satu EventEmitter
yang dapat didorong oleh fungsi layanan Anda yang berbeda.
Jika Anda ingin mengembalikan observable langsung dari panggilan Anda bisa melakukan sesuatu seperti ini:
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();
});
});
}
Itu akan memungkinkan Anda melakukan ini di komponen:
peopleService.myHttpCall('path').subscribe(people => this.people = people);
Dan mengacaukan hasil dari panggilan di layanan Anda.
Saya suka membuat EventEmitter
aliran sendiri jika saya perlu mendapatkan akses dari komponen lain, tetapi saya bisa melihat kedua cara bekerja ...
Berikut adalah plunker yang menampilkan layanan dasar dengan emitor acara: Plunkr