Использование @Output в Angular для передачи событий и данных от дочернего компонента
Что важно понять
- @Output — декоратор, который отмечает свойство компонента как источник событий для родителя.
- EventEmitter
— класс для отправки (emit) значений типа T. - Это однонаправленный механизм: дочерний компонент «выпускает» событие, родитель «подписывается» в шаблоне.
Когда использовать @Output
- Когда дочерний компонент должен сигнализировать родителю о действии (клик, выбор, ошибка).
- Когда нужно передать набор простых данных (строки, объекты, массивы) в момент события.
Быстрый план действий
- Создать приложение и компонент-родитель (app) и дочерний компонент (data-component).
- В дочернем компоненте объявить @Output() имя = new EventEmitter
(); - Вызывать this.имя.emit(параметр) при наступлении события.
- В шаблоне родителя подписаться:

Подготовка проекта и структура файлов
Предположим, что у вас есть стандартное Angular-приложение. Компонент app — родитель. Для примера создадим дочерний компонент с командой:
ng g c data-componentФайлы, с которыми мы будем работать:
- src/app/app.component.html
- src/app/app.component.css
- src/app/app.component.ts
- src/app/data-component/data-component.component.html
- src/app/data-component/data-component.component.css
- src/app/data-component/data-component.component.ts
Пример 1 — отправка простого события (void)
Шаг 1 — родитель: замените содержимое app.component.html на шаблон с контейнером:
Это родительский компонент
app.component.css:
.parent-component {
font-family: Arial, Helvetica, sans-serif;
background-color: lightcoral;
padding: 20px;
}Шаг 2 — дочерний компонент: data-component.component.html с кнопкой:
Это дочерний компонент
data-component.component.css:
.child-component {
font-family: Arial, Helvetica, sans-serif;
background-color: lightblue;
margin: 20px;
padding: 20px;
}Шаг 3 — подключаем EventEmitter в data-component.component.ts:
import { Component, Output, EventEmitter, OnInit } from '@angular/core';
@Component({
selector: 'app-data-component',
templateUrl: './data-component.component.html',
styleUrls: ['./data-component.component.css']
})
export class DataComponentComponent implements OnInit {
@Output() buttonWasClicked = new EventEmitter();
constructor() { }
ngOnInit(): void { }
onButtonClick() {
this.buttonWasClicked.emit();
}
} Шаг 4 — слушаем событие в родителе: app.component.html вставляем тег дочернего компонента и подписываемся:
{{message}}
И в app.component.ts добавляем обработчик и сообщение:
message: string = '';
buttonInChildComponentWasClicked() {
this.message = 'Кнопка в дочернем компоненте была нажата';
}Теперь при клике в дочернем компоненте родитель получит событие и отобразит сообщение.
Пример 2 — отправка данных (string[])
Если нужно передать данные при событии, указывайте обобщение EventEmitter
В data-component.component.ts добавим массив и изменим тип эмиттера:
listOfPeople: string[] = ['Joey', 'John', 'James'];
@Output() buttonWasClicked = new EventEmitter();
onButtonClick() {
this.buttonWasClicked.emit(this.listOfPeople);
} В родителе подпишемся и примем данные через $event:
{{message}}
{{data.join(', ')}}
И в app.component.ts:
message: string = '';
data: string[] = [];
buttonInChildComponentWasClicked(dataFromChild: string[]) {
this.message = 'Кнопка в дочернем компоненте была нажата';
this.data = dataFromChild;
}Полезные советы и распространённые ошибки
- Синтаксис в шаблоне: используйте (event)=’handler($event)’ — важно, что скобки указывают на событие.
- Типизация: всегда указывайте тип в EventEmitter
, чтобы избежать ошибок компиляции и иметь автодополнение. - Не пытаетесь напрямую изменять состояние родителя из дочернего — используйте событие для передачи данных.
- Не забывайте подписываться в шаблоне, а не в конструкторе через emitter.subscribe, если вам не нужна подписка с отпиской — шаблон автоматически управляет.
- Если дочерний компонент должен отправлять сложные объекты, передавайте копию (spread или structuredClone), чтобы предотвратить мутацию из родителя.
Important: если дочерний компонент эмитит событие в ngOnInit до того, как родитель успел подписаться, родитель может не получить это событие. Обычно события эмитят в ответ на пользовательские действия.
Когда @Output не подходит (контрпример)
- Нужна глобальная подписка между несвязанными компонентами — лучше использовать сервис с Subject/BehaviorSubject или менеджер состояния (NgRx, Akita).
- Требуются двусторонние связи с постоянной синхронизацией сложных объектов — рассмотрите управление состоянием или Input+Output в паре с иммутабельностью.
Альтернативные подходы
- Использовать сервис с RxJS Subject/Observable для обмена событиями между не связанными компонентами.
- Использовать Input вместе с двумя-way binding (ngModel) для формы, где требуется синхронизация.
- Для сложных приложений — централизованные хранилища состояния (NgRx, NGXS).
Контрольный список внедрения (@Output)
- Объявлен @Output с корректным типом EventEmitter
. - В дочернем компоненте вызывается emit с нужным значением.
- В шаблоне родителя подписка на (event)=’handler($event)’.
- Родитель обрабатывает входные данные и не мутирует исходные объекты дочернего компонента.
- Компиляция без ошибок типов.
Критерии приёмки
- При клике в дочернем компоненте родитель получает событие и обновляет интерфейс.
- Переданные данные в родителе соответствуют ожидаемому типу и содержимому.
- Нет утечек подписок (если подписки делаются в коде — есть отписка при destroy).
Краткая методология для команды
- Договориться об интерфейсе события: имя и тип payload.
- Типизировать EventEmitter
и параметр обработчика в родителе. - Добавить тесты компонентного поведения (симуляция клика, проверка emitted value).
- Документировать контракт события в README модуля.
Пример теста (псевдокод)
// проверить, что при клике вызывается emit с массивом
const comp = fixture.componentInstance;
spyOn(comp.buttonWasClicked, 'emit');
const button = fixture.nativeElement.querySelector('button');
button.click();
expect(comp.buttonWasClicked.emit).toHaveBeenCalledWith(comp.listOfPeople);Краткий глоссарий (1 строка)
- @Output — декоратор, помечающий событие, которое компонент может выпустить.
- EventEmitter
— класс для отправки значений типа T родителю. - $event — объект или значение, которое передаётся из дочернего компонента при подписке в шаблоне.
Безопасность и производительность
- Избегайте частого эмита больших структур данных в цикле — лучше передавать идентификатор и загружать данные по требованию.
- Если данные содержат чувствительную информацию, убедитесь, что родитель имеет право её обрабатывать и отображать.
Резюме
- @Output и EventEmitter — стандартный способ передачи событий и данных от дочернего компонента к родителю в Angular.
- Всегда типизируйте EventEmitter
и аккуратно обрабатывайте данные, чтобы избегать мутаций. - Для нереляционных сценариев рассматривайте сервисы на основе RxJS или менеджеры состояния.
Если нужно, могу добавить проверяемый пример проекта, включающий unit-тесты и e2e-проверки, или предложить шаблон соглашений по именованию событий в вашем кодбэйсе.
Похожие материалы
Как устроить идеальную вечеринку для просмотра ТВ
Как распаковать несколько RAR‑файлов сразу
Приватный просмотр в Linux: как и зачем
Windows 11 не видит iPod — способы исправить
PS5: как настроить игровые пресеты