Bagaimana cara memancarkan acara dari orang tua ke anak?


111

Saat ini saya menggunakan Angular 2. Biasanya kami menggunakan @Output() addTab = new EventEmitter<any>();dan kemudian addTab.emit()memancarkan acara ke komponen induk.

Adakah cara yang bisa kita lakukan wakil cersa, dari orang tua ke anak?


2
Ubah saja nilai ekspresi yang diteruskan sebagai Input ke komponen anak, dan komponen anak akan mendapatkannya (dan diinformasikan oleh ngOnChanges). Anda juga dapat memancarkan acara menggunakan layanan bersama yang memiliki Observable.
JB Nizet

Jawaban:


192

Dengan menggunakan RxJs , Anda dapat mendeklarasikan a Subjectdalam komponen induk Anda dan meneruskannya Observableke komponen anak, komponen anak hanya perlu berlangganan ini Observable.

Komponen Induk

eventsSubject: Subject<void> = new Subject<void>();

emitEventToChild() {
  this.eventsSubject.next();
}

Parent-HTML

<child [events]="eventsSubject.asObservable()"> </child>    

Komponen Anak

private eventsSubscription: Subscription;

@Input() events: Observable<void>;

ngOnInit(){
  this.eventsSubscription = this.events.subscribe(() => doSomething());
}

ngOnDestroy() {
  this.eventsSubscription.unsubscribe();
}

13
Selain itu, data dapat diteruskan bersama acara tersebut menggunakan pendekatan ini. Seperti, this.eventsSubject.next({data});pada orang tua, lalu this.events.subscribe(({data}) => doSomething(data));pada anak.
vince

2
Saya telah mengedit jawaban yang bagus ini untuk menambahkan berhenti berlangganan. +1
Umar Farooq Khawaja

1
Mungkin pertanyaan pemula di sini: Mengapa mengonversi eventsSubjectke Observable daripada hanya berlangganan sebagai Subjek?
Justin Morgan

11
Mengonversi eventsSubject menjadi Observable, mencegah komponen anak memanggil next ().
BlueNC

2
Terima kasih untuk solusi ini, ITU BERFUNGSI tetapi saya mendapatkan kesalahan di konsol: "core.js: 6185 ERROR TypeError: Tidak dapat membaca properti 'subscribe' dari undefined" Kesalahan menunjuk ke event.subscribe () di ngOnInit komponen turunan: "this.eventsSubscription = this.events.subscribe (() => doSomething ());" Saya menggunakan versi: "@ angular / cli": "~ 9.1.0" dan "rxjs" : "~ 6.5.4"
Eduardo

72

Sejauh yang saya tahu, ada 2 cara standar untuk melakukannya.

1. @Input

Setiap kali data dalam induk berubah, anak akan diberi tahu tentang hal ini dalam metode ngOnChanges. Anak itu bisa bertindak berdasarkan itu. Ini adalah cara standar berinteraksi dengan seorang anak.

Parent-Component
public inputToChild: Object;

Parent-HTML
<child [data]="inputToChild"> </child>       

Child-Component: @Input() data;

ngOnChanges(changes: { [property: string]: SimpleChange }){
   // Extract changes to the input property by its name
   let change: SimpleChange = changes['data']; 
// Whenever the data in the parent changes, this method gets triggered. You 
// can act on the changes here. You will have both the previous value and the 
// current value here.
}
  1. Konsep layanan bersama

Membuat layanan dan menggunakan yang dapat diamati di layanan bersama. Anak itu berlangganan dan setiap kali ada perubahan, anak itu akan diberi tahu. Ini juga merupakan metode yang populer. Ketika Anda ingin mengirim sesuatu selain data yang Anda berikan sebagai input, ini dapat digunakan.

SharedService
subject: Subject<Object>;

Parent-Component
constructor(sharedService: SharedService)
this.sharedService.subject.next(data);

Child-Component
constructor(sharedService: SharedService)
this.sharedService.subject.subscribe((data)=>{

// Whenever the parent emits using the next method, you can receive the data 
in here and act on it.})

Saya mencoba metode pertama dan berfungsi dengan baik sampai beberapa titik dan setelah itu saya mendapat pesan kesalahan yang menyatakan Nilai diubah sekarang, sebelumnya itu salah dan sekarang itu benar. Itu tidak memberi saya penjelasan lebih lanjut selain ini.
kode1

2
Yang Anda maksud adalah ExpressionChangedAfterItHasBeenCheckedError, kesalahan ini tidak akan ditampilkan dalam mode produksi.
pengguna1337

<child [data]="inputToChild"> </child>mungkin harus <child [data]="(inputToChild)"> </child>mendapatkan perubahan
pmc

28

Dalam komponen induk, Anda bisa menggunakan @ViewChild () untuk mengakses metode / variabel komponen anak.

@Component({
  selector: 'app-number-parent',
  templateUrl: './number-parent.component.html'
})
export class NumberParentComponent {
    @ViewChild(NumberComponent)
    private numberComponent: NumberComponent;
    increase() {
       this.numberComponent.increaseByOne();
    }
    decrease() {
       this.numberComponent.decreaseByOne();
    }
} 

Memperbarui:

Angular 8 dan seterusnya -

@ViewChild(NumberComponent, { static: false })

4
Ini tampak lebih bersih daripada bekerja dengan observable. Kekurangannya adalah child harus di lihat. Jika anak yang sarat dengan routing untuk contoh, ini akan gagal sebagai numberComponentakan undefined.
Shy Agam

1
apakah ini praktik yang baik? Saya setuju dengan fakta yang lebih bersih daripada yang dapat diamati, tetapi saya ragu tentang memanipulasi variabel anak dari orang tua. Bagaimanapun, itu bekerja sangat baik untuk kebutuhan saya, Terima kasih!
Takatalvi

1
Ini tip yang bagus. Sepertinya @ViewChild diubah di Angular 8, atau setidaknya saya harus menentukan opsi ViewChild. Saya menggunakan ini dalam kasus saya: @ViewChild (Other, {static: false}) private otherComponent: Other;
Tore Aurstad

8

Gunakan dekorator @Input () dalam komponen anak Anda untuk memungkinkan induk mengikat masukan ini.

Dalam komponen anak Anda mendeklarasikannya apa adanya:

@Input() myInputName: myType

Untuk mengikat properti dari induk ke anak, Anda harus menambahkan dalam templat Anda tanda kurung pengikat dan nama input Anda di antara keduanya.

Contoh:

<my-child-component [myChildInputName]="myParentVar"></my-child-component>

Namun berhati-hatilah, objek diteruskan sebagai referensi, jadi jika objek diperbarui pada anak, var induknya akan terlalu diperbarui. Hal ini terkadang dapat menyebabkan beberapa perilaku yang tidak diinginkan. Dengan tipe primer nilainya disalin.

Untuk membaca lebih lanjut ini:

Docs: https://angular.io/docs/ts/latest/cookbook/component-communication.html


1

Di dalam induk, Anda bisa mereferensikan anak menggunakan @ViewChild. Jika diperlukan (misalnya, saat acara akan diaktifkan), Anda cukup menjalankan metode pada anak dari induk menggunakan referensi @ViewChild.

Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.