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
EventEmitter
untuk apa pun tetapi@Output()
tidak dianjurkan. Lihat juga stackoverflow.com/questions/34376854/…Ini adalah contoh dari dokumen Angular2 tentang bagaimana Anda dapat membuat dan menggunakan Observables Anda sendiri:
Layanan
Komponen
Contoh lengkap dan berfungsi dapat ditemukan di sini: https://angular.io/docs/ts/latest/cookbook/component-communication.html#!#bidirectional-service
sumber
Saya ingin menambahkan bahwa jika objek yang dibuat adalah statis dan tidak datang melalui http sesuatu seperti itu dapat dilakukan:
Sunting: Untuk pemetaan 7.xx Angular perlu dilakukan dengan menggunakan pipa () seperti yang dijelaskan di sini ( https://stackoverflow.com/a/54085359/986160 ):
dari jawaban pertanyaan saya tentang pengamat dan data statis: https://stackoverflow.com/a/35219772/986160
sumber
Saya sedikit terlambat ke pesta, tapi saya pikir pendekatan saya memiliki keuntungan karena kurang menggunakan EventEmitter dan Subjek.
Jadi, inilah pendekatan saya. Kami tidak dapat menghindar dari berlangganan (), dan kami tidak mau. Dalam nada itu, layanan kami akan mengembalikan sebuah
Observable<T>
dengan pengamat yang memiliki barang berharga kami. Dari pemanggil, kami akan menginisialisasi variabelObservable<T>
,, dan itu akan mendapatkan layananObservable<T>
. Selanjutnya, kami akan berlangganan objek ini. Akhirnya, Anda mendapatkan "T" Anda! dari layanan Anda.Pertama, layanan orang kami, tetapi milik Anda tidak lulus parameter, itu lebih realistis:
Oke, seperti yang Anda lihat, kami mengembalikan
Observable
jenis "orang". Tanda tangan dari metode ini, bahkan mengatakan demikian! Kami memasukkan_people
benda itu ke pengamat kami. Kami akan mengakses jenis ini dari pemanggil kami di Komponen, selanjutnya!Dalam Komponen:
Kami menginisialisasi
_peopleObservable
dengan mengembalikan ituObservable<people>
dari kamiPeopleService
. Kemudian, kami berlangganan properti ini. Akhirnya, kami menetapkan responsthis.people
data (people
) kami.Merancang layanan dengan cara ini memiliki satu keunggulan utama dibandingkan layanan khas: map (...) dan komponen: pola "berlangganan (...)". Di dunia nyata, kita perlu memetakan json ke properti kita di kelas kita dan, kadang-kadang, kita melakukan beberapa hal khusus di sana. Jadi pemetaan ini dapat terjadi di layanan kami. Dan, biasanya, karena panggilan layanan kami akan digunakan tidak hanya sekali, tetapi, mungkin, di tempat lain dalam kode kami, kami tidak perlu melakukan pemetaan itu di beberapa komponen, lagi. Apalagi, bagaimana jika kita menambahkan bidang baru ke orang-orang? ....
sumber
Dalam file service.ts -
Sebuah. impor 'dari' dari yang dapat diamati / dari
b. buat daftar json
c. mengembalikan objek json menggunakan Observable.of ()
Ex. -
Dalam komponen di mana kita memanggil fungsi get dari layanan -
sumber
Perhatikan bahwa Anda menggunakan peta # yang dapat diobservasi untuk mengonversi
Response
objek mentah yang dipancarkan oleh basis Anda menjadi representasi yang diuraikan dari respons JSON.Jika saya mengerti Anda dengan benar, Anda ingin
map
lagi. Tapi kali ini, ubah JSON mentah itu menjadi instance dari AndaModel
. Jadi, Anda akan melakukan sesuatu seperti:Jadi, Anda mulai dengan Observable yang memancarkan
Response
objek, mengubahnya menjadi observable yang memancarkan objek dari JSON yang diuraikan respon itu, dan kemudian mengubahnya menjadi lagi yang bisa diamati yang mengubah JSON mentah itu menjadi array model Anda.sumber