Як передавати подію від батька до дитини?


111

В даний час я використовую Angular 2. Зазвичай ми використовуємо, @Output() addTab = new EventEmitter<any>();а потім передаємо addTab.emit()подію батьківському компоненту.

Чи існує спосіб, коли ми можемо це зробити віце-церсі, від батька до дитини?


2
Просто змініть значення виразу, переданого як Вхід до дочірнього компонента, і дочірній компонент отримає його (і буде проінформований ngOnChanges). Ви також можете передавати подію за допомогою спільної служби, яка має спостережуване.
JB Nizet

Відповіді:


192

Використовуючи RxJs , ви можете оголосити a Subjectу своєму батьківському компоненті та передати його Observableдочірньому компоненту, дочірній компонент просто повинен підписатися на це Observable.

Батько-компонент

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

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

Parent-HTML

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

Дочірній компонент

private eventsSubscription: Subscription;

@Input() events: Observable<void>;

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

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

13
Також дані можуть передаватися разом із подією, використовуючи такий підхід. Мовляв, this.eventsSubject.next({data});у батьків, потім this.events.subscribe(({data}) => doSomething(data));у дитини.
vince

2
Я відредагував цю чудову відповідь, щоб додати підписку. +1
Умар Фарук Хавая

1
Можливо, питання для початківців тут: навіщо перетворюватися eventsSubjectна спостережуване, а не просто підписуватися на нього як на предмет?
Джастін Морган

11
Перетворення подійSubject у спостережуване, не дозволяйте дочірньому компоненту викликати next ().
BlueNC

2
Дякую за це рішення, він працює, але я отримую помилку в консолі: "core.js: 6185 ПОМИЛКА TypeError: Не вдається прочитати властивість" підписатися "на невизначене" Помилка вказує на події.subscribe () у ngOnInit дочірнього компонента: "this.eventsSubscription = this.events.subscribe (() => doSomething ());" Я використовую версії: "@ angular / cli": "~ 9.1.0" та "rxjs" : "~ 6.5.4"
Едуардо

72

Наскільки я знаю, є 2 стандартних способи зробити це.

1. @ Введення

Щоразу, коли дані батьків змінюються, дитина отримує про це повідомлення методом ngOnChanges. На це може діяти дитина. Це стандартний спосіб взаємодії з дитиною.

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. Концепція спільного обслуговування

Створення послуги та використання спостережуваного в спільній службі. Дитина підписується на це і кожного разу, коли відбудеться зміна, про це буде повідомлено дитину. Це також популярний метод. Коли ви хочете надіслати щось інше, ніж ті дані, які ви передаєте у якості вхідних даних, це можна використовувати.

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

Я спробував перший метод, і він працював чудово до певного моменту, і після цього я отримав повідомлення про помилку, в якому говорилося, що значення змінилося зараз, раніше це помилково, а тепер це правда. Окрім цього, це не дало мені більше пояснень.
код1

2
Враховуючи, що ви маєте на увазі ExpressionChangedAfterItHasBeenCheckedError, ця помилка не буде передана у виробничому режимі.
user1337

<child [data]="inputToChild"> </child>Мабуть, варто <child [data]="(inputToChild)"> </child>отримати зміни
pmc

28

У батьківському компоненті ви можете використовувати @ViewChild () для доступу до методу / змінної дочірнього компонента.

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

Оновлення:

Кутовий 8 далі -

@ViewChild(NumberComponent, { static: false })

4
Це здається чистішим, ніж робота з спостережними. Недолік дитини має бути в зорі. Якщо, наприклад, дитина завантажена маршрутизацією, це не вдасться, як numberComponentбуде undefined.
Сором’язливий

1
це хороша практика? Я погоджуюся з тим, що чистіше за спостереження, але я сумніваюся в маніпулюванні змінами дитини від батьків. У всякому разі, це спрацювало так добре для моїх потреб, Дякую!
Такатальві

1
Це хороша порада. Схоже, @ViewChild змінено у Angular 8, або, принаймні, мені довелося вказати параметри ViewChild. Я використовував це у своєму випадку: @ViewChild (Інше, {static: false}) private otherComponent: Other;
Торе Аурстад

8

Використовуйте декоратор @Input () у своєму дочірньому компоненті, щоб дозволити батькові прив’язатись до цього вводу.

У дочірньому компоненті ви заявляєте це як:

@Input() myInputName: myType

Щоб прив’язати властивість від батька до дитини, ви повинні додати у свій шаблон дужки прив'язки та ім'я вводу між ними.

Приклад:

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

Але будьте обережні, об'єкти передаються як орієнтир, тому, якщо об’єкт буде оновлено у дочірніх, вар батьків буде занадто оновленим. Це може призвести до небажаної поведінки колись. При первинних типах значення копіюється.

Щоб продовжити, прочитайте це:

Документи: https://angular.io/docs/ts/latest/cookbook/component-communication.html


1

У межах батьків ви можете посилатися на дитину за допомогою @ViewChild. У разі необхідності (тобто, коли подія буде запущена), ви можете просто виконати метод у дитини від батьків, використовуючи посилання @ViewChild.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.