Как обработать событие из дочернего компонента в родительском?angular-24

Основные способы обработки событий

1. Output-свойства + EventEmitter

Дочерний компонент:

import { Output, EventEmitter } from '@angular/core';

@Output() buttonClicked = new EventEmitter<string>();

onClick() {
  this.buttonClicked.emit('Данные события');
}

Родительский компонент:

<app-child (buttonClicked)="handleChildEvent($event)"></app-child>
handleChildEvent(data: string) {
  console.log('Событие из дочернего компонента:', data);
}

2. Шаблонные переменные + ViewChild

Родительский компонент:

<app-child #childRef></app-child>
<button (click)="childRef.onClick()">Вызвать метод дочернего</button>
import { ViewChild } from '@angular/core';
import { ChildComponent } from './child.component';

@ViewChild('childRef') childComponent: ChildComponent;

handleClick() {
  this.childComponent.onClick();
}

3. Через сервис с Subject/Observable

Создаем сервис:

@Injectable({ providedIn: 'root' })
export class EventService {
  private childEventSource = new Subject<string>();
  childEvent$ = this.childEventSource.asObservable();

  emitEvent(data: string) {
    this.childEventSource.next(data);
  }
}

Дочерний компонент:

constructor(private eventService: EventService) {}

triggerEvent() {
  this.eventService.emitEvent('Данные события');
}

Родительский компонент:

constructor(private eventService: EventService) {
  this.eventService.childEvent$.subscribe(data => {
    console.log('Событие через сервис:', data);
  });
}

Дополнительные методы

4. Двусторонняя привязка []

Полезно, когда нужно одновременно:

  • Передавать данные в дочерний компонент
  • Получать изменения этих данных обратно

Дочерний компонент:

@Input() value: string;
@Output() valueChange = new EventEmitter<string>();

updateValue(newValue: string) {
  this.value = newValue;
  this.valueChange.emit(newValue);
}

Родительский компонент:

<app-child [(value)]="parentValue"></app-child>

Когда какой метод использовать?

Метод Когда использовать Плюсы Минусы
Output + EventEmitter Стандартные события компонента Чистый Angular подход Только для прямых потомков
Сервис с Observable Компоненты без прямого отношения Гибкость Сложнее отладка
ViewChild Нужен прямой доступ к методам Полный контроль Нарушает инкапсуляцию
Двусторонняя привязка Синхронизация значения Удобный синтаксис Ограниченный случай

Лучшие практики

  1. Используйте EventEmitter для стандартных случаев
  2. Типизируйте события:
@Output() userSelected = new EventEmitter<User>();
  1. Отписывайтесь от Observable в сервисном подходе:
private destroy$ = new Subject();

ngOnInit() {
  this.eventService.childEvent$
    .pipe(takeUntil(this.destroy$))
    .subscribe(...);
}

ngOnDestroy() {
  this.destroy$.next();
  this.destroy$.complete();
}
  1. Избегайте сложной логики в шаблоне:
<!-- Плохо -->
<app-child (click)="value = value + 1"></app-child>

<!-- Хорошо -->
<app-child (click)="handleClick()"></app-child>

Резюмируем

  1. Основной способ - Output свойства с EventEmitter
  2. Альтернативные методы:
    • Сервис с Observable (для несвязанных компонентов)
    • ViewChild (для прямого доступа к методам)
    • Двусторонняя привязка (для синхронизации значений)
  3. Рекомендации:
    • Соблюдайте принцип единой ответственности
    • Типизируйте передаваемые события
    • Управляйте подписками на Observable
    • Избегайте tight coupling между компонентами

Правильная обработка событий делает компоненты переиспользуемыми и поддерживаемыми.