Saya mencoba menerapkan sesuatu seperti pola delegasi di Angular. Ketika pengguna mengklik a nav-item
, saya ingin memanggil fungsi yang kemudian memancarkan suatu peristiwa yang pada gilirannya harus ditangani oleh beberapa komponen lain yang mendengarkan acara tersebut.
Berikut ini skenarionya: Saya punya Navigation
komponen:
import {Component, Output, EventEmitter} from 'angular2/core';
@Component({
// other properties left out for brevity
events : ['navchange'],
template:`
<div class="nav-item" (click)="selectedNavItem(1)"></div>
`
})
export class Navigation {
@Output() navchange: EventEmitter<number> = new EventEmitter();
selectedNavItem(item: number) {
console.log('selected nav item ' + item);
this.navchange.emit(item)
}
}
Berikut adalah komponen yang mengamati:
export class ObservingComponent {
// How do I observe the event ?
// <----------Observe/Register Event ?-------->
public selectedNavItem(item: number) {
console.log('item index changed!');
}
}
Pertanyaan kuncinya adalah, bagaimana cara membuat komponen mengamati mengamati peristiwa yang dimaksud?
Jawaban:
Pembaruan 2016-06-27: alih-alih menggunakan Observables, gunakan keduanya
Sebuah Subyek adalah baik diamati (sehingga kita bisa
subscribe()
untuk itu) dan Pengamat (sehingga kita bisa menyebutnyanext()
di atasnya untuk memancarkan nilai baru). Kami memanfaatkan fitur ini. Subjek memungkinkan nilai menjadi multicast bagi banyak Pengamat. Kami tidak mengeksploitasi fitur ini (kami hanya memiliki satu Pengamat).BehaviorSubject adalah varian dari Subjek. Ini memiliki gagasan "nilai saat ini". Kami mengeksploitasi ini: setiap kali kami membuat ObservingComponent, ia mendapatkan nilai item navigasi saat ini dari BehaviorSubject secara otomatis.
Kode di bawah ini dan plunker menggunakan BehaviorSubject.
ReplaySubject adalah varian lain dari Subjek. Jika Anda ingin menunggu hingga nilai benar-benar dihasilkan, gunakan
ReplaySubject(1)
. Sedangkan BehaviorSubject membutuhkan nilai awal (yang akan segera disediakan), ReplaySubject tidak. ReplaySubject akan selalu memberikan nilai terbaru, tetapi karena tidak memiliki nilai awal yang diperlukan, layanan dapat melakukan beberapa operasi async sebelum mengembalikan nilai pertama. Itu akan tetap aktif segera pada panggilan berikutnya dengan nilai terbaru. Jika Anda hanya ingin satu nilai, gunakanfirst()
pada berlangganan. Anda tidak harus berhenti berlangganan jika menggunakanfirst()
.Plunker
Jawaban asli yang menggunakan Observable: (memerlukan lebih banyak kode dan logika daripada menggunakan BehaviorSubject, jadi saya tidak merekomendasikannya, tetapi mungkin instruktif)
Jadi, inilah implementasi yang menggunakan Observable alih-alih EventEmitter . Tidak seperti implementasi EventEmitter saya, implementasi ini juga menyimpan yang saat ini dipilih
navItem
dalam layanan, sehingga ketika komponen mengamati dibuat, itu dapat mengambil nilai saat ini melalui panggilan APInavItem()
, dan kemudian diberitahu tentang perubahan melaluinavChange$
Observable.Plunker
Lihat juga contoh Cookbook Interaksi Komponen , yang menggunakan
Subject
selain yang bisa diamati. Meskipun contohnya adalah "komunikasi orang tua dan anak-anak," teknik yang sama berlaku untuk komponen yang tidak terkait.sumber
EventEmitter
mana pun kecuali untuk output. Mereka saat ini sedang menulis ulang tutorial (AFAIR komunikasi server) untuk tidak mendorong praktik ini._observer
objek layanan setidaknya tidak diinisialisasi pada saatngOnInit()
komponen Navigasi dipanggil.EventEmitter
karena "panas" yang berarti sudah "dibagikan", dirancang untuk menyimpan nilai saat ini dan akhirnya menerapkan Observable dan Observer yang akan menyelamatkan Anda setidaknya lima baris kode dan dua propertisubscribe()
, sehingga tidak dapat mendeteksi kapan perubahan yang diamati. Biasanya, ada beberapa peristiwa async yang menyala (dalam kode sampel saya, ini adalah peristiwa klik tombol), dan panggilan balik yang terkait akan memanggil next () pada yang bisa diamati. Tetapi deteksi perubahan berjalan karena peristiwa async, bukan karena perubahan yang dapat diamati. Lihat juga komentar Günter: stackoverflow.com/a/36846501/215945ReplaySubject(1)
. ABehaviorSubject
membutuhkan nilai awal yang akan segera disediakan. ItuReplaySubject(1)
akan selalu memberikan nilai terbaru, tetapi tidak memiliki nilai awal yang diperlukan sehingga layanan dapat melakukan beberapa operasi async sebelum mengembalikan nilai pertama itu, tetapi masih langsung aktif pada panggilan berikutnya dengan nilai terakhir. Jika Anda hanya tertarik pada satu nilai yang dapat Anda gunakanfirst()
pada langganan dan tidak harus berhenti berlangganan pada akhirnya karena itu akan selesai.Berita terkini: Saya telah menambahkan jawaban lain yang menggunakan Observable daripada EventEmitter. Saya merekomendasikan jawaban itu untuk yang satu ini. Dan sebenarnya, menggunakan EventEmitter dalam layanan adalah praktik yang buruk .
Jawaban asli: (jangan lakukan ini)
Masukkan EventEmitter ke dalam layanan, yang memungkinkan PengamatComponent untuk langsung berlangganan (dan berhenti berlangganan) ke acara:Jika Anda mencoba Plunker, ada beberapa hal yang saya tidak suka tentang pendekatan ini:
subscribe()
agar tepatthis
diatur ketika panggilan balik dipanggilPembaruan: Alternatif yang memecahkan peluru ke-2 adalah memiliki ObservingComponent secara langsung berlangganan
navchange
properti EventEmitter:Jika kami berlangganan secara langsung, maka kami tidak akan memerlukan
subscribe()
metode di NavService.Untuk membuat NavService sedikit lebih dienkapsulasi, Anda bisa menambahkan
getNavChangeEmitter()
metode dan menggunakannya:sumber
this.subscription = this.navService.subscribe(() => this.selectedNavItem());
dan berlangganan:return this.navchange.subscribe(callback);
Jika seseorang ingin mengikuti gaya pemrograman yang lebih Reaktif, maka pasti konsep "Semuanya adalah aliran" muncul dan karenanya, gunakan Observable untuk menangani aliran ini sesering mungkin.
sumber
Anda dapat menggunakan:
BehaviorSubject adalah jenis subjek, subjek adalah jenis khusus yang dapat diamati yang dapat bertindak sebagai diamati dan pengamat Anda dapat berlangganan pesan seperti diamati lainnya dan setelah berlangganan, itu mengembalikan nilai terakhir dari subjek yang dipancarkan oleh sumber yang diamati:
Keuntungan: Tidak Ada Hubungan seperti hubungan orangtua-anak yang diperlukan untuk meneruskan data antar komponen.
LAYANAN NAV
KOMPONEN NAVIGASI
KOMPONEN PENGAMATAN
Pendekatan kedua adalah
Event Delegation in upward direction child -> parent
misalnya Dijawab diberikan oleh @Ashish Sharma.
sumber
Anda perlu menggunakan komponen Navigasi dalam templat ObservingComponent (jangan lupa menambahkan pemilih ke komponen Navigasi .. komponen navigasi untuk ex)
Dan mengimplementasikan onNavGhange () di ObservingComponent
Hal terakhir .. Anda tidak perlu atribut acara di @Componennt
sumber
nav-item
tapi saya hanya ingin memancarkan suatu peristiwa yang orang lain dapat amati.Anda dapat menggunakan BehaviourSubject seperti dijelaskan di atas atau ada satu cara lagi:
Anda dapat menangani EventEmitter seperti ini: pertama-tama tambahkan pemilih
Sekarang Anda dapat menangani acara ini seperti izinkan kami mengira observer.component.html adalah tampilan komponen Observer
kemudian di ObservingComponent.ts
sumber
Saya menemukan solusi lain untuk kasus ini tanpa menggunakan Reactivex maupun layanan. Saya benar-benar menyukai API rxjx namun saya pikir ini akan lebih baik ketika menyelesaikan fungsi async dan / atau kompleks. Menggunakannya dengan cara itu, itu sangat melebihi saya.
Apa yang saya pikir Anda cari adalah siaran. Hanya itu saja. Dan saya menemukan solusi ini:
Ini adalah contoh yang berfungsi penuh: https://plnkr.co/edit/xGVuFBOpk2GP0pRBImsE
sumber