Ebeveynden çocuğa bir olay nasıl yayılır?


112

Şu anda Angular 2 kullanıyorum. Genellikle @Output() addTab = new EventEmitter<any>();ve daha sonra addTab.emit()ana bileşene bir olay yaymak için kullanırız.

Ebeveynden çocuğa cersa yardımcısı yapmanın bir yolu var mı?


2
Alt bileşene Giriş olarak iletilen bir ifadenin değerini değiştirirseniz, alt bileşen onu alır (ve ngOnChanges tarafından bilgilendirilir). Gözlemlenebilir bir paylaşılan hizmeti kullanarak da bir olay yayınlayabilirsiniz.
JB Nizet

Yanıtlar:


193

RxJ'leri kullanarak , Subjectüst bileşeninizde bir tanımlayabilir ve onu Observablealt bileşen olarak iletebilirsiniz , alt bileşenin sadece buna abone olması gerekir Observable.

Ana Bileşen

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

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

Ebeveyn-HTML

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

Alt Bileşen

private eventsSubscription: Subscription;

@Input() events: Observable<void>;

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

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

13
Ayrıca, bu yaklaşım kullanılarak olay ile birlikte veriler de aktarılabilir. Mesela this.eventsSubject.next({data});ebeveynde, sonra this.events.subscribe(({data}) => doSomething(data));çocukta.
vince

2
Aboneliği iptal etmek için bu harika yanıtı düzenledim. +1
Umar Farooq Khawaja

1
Muhtemelen burada yeni başlayanlar için bir soru: Neden eventsSubjectsadece Konu olarak abone olmak yerine bir Gözlemlenebilirliğe dönüştürülsün ?
Justin Morgan

11
Olayları bir Gözlemlenebilir konuya dönüştürmek, alt bileşenin next () öğesini çağırmasını engelleyin.
BlueNC

2
Bu çözüm için teşekkürler, ÇALIŞIYOR, ancak konsolda bir hata alıyorum: "core.js: 6185 HATA TypeError: Tanımsız 'abonelik' özelliği okunamıyor" Hata, ngOnInit'teki events.subscribe () öğesini işaret ediyor alt bileşenin: "this.eventsSubscription = this.events.subscribe (() => doSomething ());" Şu sürümleri kullanıyorum: "@ angular / cli": "~ 9.1.0" ve "rxjs" : "~ 6.5.4"
Eduardo

72

Bildiğim kadarıyla bunu yapmanın 2 standart yolu var.

1. @ Giriş

Ebeveyndeki veriler her değiştiğinde, çocuk ngOnChanges yönteminde bu konuda bilgilendirilir. Çocuk buna göre hareket edebilir. Bu, bir çocukla etkileşim kurmanın standart yoludur.

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. Paylaşılan hizmet anlayışı

Bir hizmet oluşturmak ve paylaşılan hizmette bir gözlemlenebiliri kullanmak. Çocuk buna abone olur ve her değişiklik olduğunda çocuk bilgilendirilir. Bu aynı zamanda popüler bir yöntemdir. Giriş olarak ilettiğiniz verilerden başka bir şey göndermek istediğinizde, bu kullanılabilir.

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.})

İlk yöntemi denedim ve bir noktaya kadar iyi çalıştı ve bundan sonra değerin şimdi değiştiğini, daha önce yanlış olduğunu ve şimdi doğru olduğunu belirten bir hata mesajı aldım. Bana bunun dışında herhangi bir açıklama yapmadı.
kod1

2
Bir ExpressionChangedAfterItHasBeenCheckedError demek istediğiniz için, bu hata üretim modunda atılmayacaktır.
user1337

<child [data]="inputToChild"> </child>muhtemelen <child [data]="(inputToChild)"> </child>değişiklikleri almak için olmalı
pmc

28

Bir üst bileşende, alt bileşenin yöntemine / değişkenine erişmek için @ViewChild () öğesini kullanabilirsiniz.

@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();
    }
} 

Güncelleme:

Açısal 8'den itibaren -

@ViewChild(NumberComponent, { static: false })

4
Bu, gözlemlenebilirlerle çalışmaktan daha temiz görünüyor. Dezavantajı, çocuğun görüş alanında olması gerektiğidir. Çocuk örneğin yönlendirme ile yüklenirse, bu kadar başarısız olur numberComponentolacaktır undefined.
Shy Agam

1
bu iyi bir uygulama mı? Gözlenebilirlerden daha temiz olduğu gerçeğine katılıyorum, ancak çocuğun değişkenlerini ebeveynden manipüle etmekten şüphe duyuyorum. Neyse, ihtiyaçlarım için çok iyi çalıştı, teşekkürler!
Takatalvi

1
Bu iyi bir ipucu. Görünüşe göre @ViewChild Angular 8'de değiştirildi veya en azından ViewChild'in seçeneklerini belirtmem gerekiyordu. Bunu benim durumumda kullandım: @ViewChild (Other, {static: false}) private otherComponent: Other;
Tore Aurstad

8

Ebeveynin bu girdiye bağlanmasına izin vermek için alt bileşeninizde @Input () dekoratörünü kullanın.

Alt bileşende olduğu gibi beyan edersiniz:

@Input() myInputName: myType

Bir özelliği ebeveynden bir çocuğa bağlamak için, bağlama parantezlerini ve aralarındaki girişinizin adını şablonunuza eklemeniz gerekir.

Misal :

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

Ancak dikkat edin, nesneler bir referans olarak aktarılır, bu nedenle nesne çocukta güncellenirse, ebeveynin değişkeni fazla güncellenir. Bu bazen bazı istenmeyen davranışlara yol açabilir. Birincil türlerde değer kopyalanır.

Daha ileri gitmek için şunu okuyun:

Dokümanlar: https://angular.io/docs/ts/latest/cookbook/component-communication.html


1

Üst öğe içinde, @ViewChild kullanarak çocuğa başvurabilirsiniz. Gerektiğinde (yani olay tetiklendiğinde), @ViewChild referansını kullanarak üst öğedeki alt öğede bir yöntemi çalıştırabilirsiniz.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.