Comunicación hijo-padre
La comunicación hijo-padre es el patrón complementario a la comunicación padre-hijo que ya conoces. Mientras que con @Input
el componente padre envía datos al hijo, en este caso necesitamos que el componente hijo pueda notificar eventos o enviar información de vuelta a su componente padre.
Cuándo necesitamos comunicación hijo-padre
Imagina estos escenarios comunes en aplicaciones reales:
- Un botón personalizado que debe notificar al componente padre cuando se hace clic
- Un formulario hijo que necesita informar cuando se ha enviado correctamente
- Una lista de productos donde cada item debe notificar cuando se selecciona o elimina
- Un modal o diálogo que debe avisar cuando se cierra o se confirma una acción
En todos estos casos, el componente hijo necesita "hablar hacia arriba" en la jerarquía de componentes.
El problema de la comunicación unidireccional
Angular sigue un flujo de datos unidireccional: los datos fluyen naturalmente de padre a hijo. Esto es excelente para la predictibilidad y el rendimiento, pero crea un desafío cuando el hijo necesita comunicarse con el padre.
// ❌ Esto no es posible - el hijo no puede acceder directamente al padre
export class ComponenteHijo {
enviarDatos() {
this.componentePadre.recibirDatos(datos); // No funciona así
}
}
La solución: eventos personalizados
La comunicación hijo-padre en Angular funciona mediante eventos personalizados. Es similar a como los elementos HTML nativos emiten eventos (como click
, change
, submit
) que puedes escuchar desde su contenedor.
El patrón funciona así:
1. El componente hijo emite un evento personalizado
// El hijo "dispara" un evento con datos
this.eventoPersonalizado.emit(datos);
2. El componente padre escucha ese evento
<!-- El padre "escucha" el evento como cualquier otro evento DOM -->
<componente-hijo (eventoPersonalizado)="manejarEvento($event)"></componente-hijo>
Ejemplo conceptual: botón personalizado
Considera un botón personalizado que debe notificar diferentes tipos de clics:
// Componente hijo - Botón personalizado
export class BotonPersonalizado {
// El botón puede emitir diferentes eventos
notificarClickSimple() {
// Evento sin datos
}
notificarClickConDatos() {
// Evento con información adicional
}
}
<!-- Componente padre - Usa el botón -->
<boton-personalizado
(clickSimple)="manejarClick()"
(clickConDatos)="manejarClickEspecial($event)">
</boton-personalizado>
Ventajas de este patrón
El sistema de eventos hijo-padre de Angular ofrece varios beneficios:
- Desacoplamiento: El hijo no necesita conocer los detalles del padre
- Reutilización: El mismo componente hijo puede usarse con diferentes padres
- Flexibilidad: El padre decide cómo manejar cada evento
- Consistencia: Usa la misma sintaxis que los eventos DOM nativos
Comparación con la comunicación padre-hijo
| Comunicación padre-hijo (@Input) | Comunicación hijo-padre (eventos) |
|----------------------------------|-----------------------------------|
| Envía datos del padre al hijo | Envía notificaciones del hijo al padre |
| Sintaxis: [propiedad]="valor"
| Sintaxis: (evento)="manejador($event)"
|
| Flujo: Padre → Hijo | Flujo: Hijo → Padre |
| Para: Configurar el componente | Para: Reaccionar a acciones del usuario |
Esta comunicación bidireccional (padre→hijo con @Input
e hijo→padre con eventos) forma la base de la interacción entre componentes en Angular, permitiendo crear interfaces de usuario dinámicas y reactivas donde los componentes pueden colaborar de forma eficiente.
Introducción a @Output y EventEmitter
Ahora que entiendes el concepto de comunicación hijo-padre, es momento de ver cómo implementarlo técnicamente en Angular usando @Output
y EventEmitter
. Estas son las herramientas que Angular proporciona para crear eventos personalizados en tus componentes.
El decorador @Output
El decorador @Output marca una propiedad del componente como un evento que puede ser escuchado desde el componente padre. Es el mecanismo que hace posible la comunicación ascendente en la jerarquía de componentes.
import { Component, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-contador',
template: `
<div>
<p>Valor actual: {{ contador }}</p>
<button (click)="incrementar()">+1</button>
<button (click)="decrementar()">-1</button>
</div>
`
})
export class ContadorComponent {
contador = 0;
// Declaramos un evento personalizado
@Output() valorCambiado = new EventEmitter<number>();
incrementar() {
this.contador++;
this.valorCambiado.emit(this.contador); // Emitimos el nuevo valor
}
decrementar() {
this.contador--;
this.valorCambiado.emit(this.contador); // Emitimos el nuevo valor
}
}
La clase EventEmitter
EventEmitter es una clase especial de Angular que extiende la funcionalidad de RxJS para crear eventos personalizados. Actúa como un canal de comunicación que puede emitir valores hacia el componente padre.
Anatomía de un @Output
Cada @Output
sigue un patrón consistente:
1. Declaración del evento
@Output() nombreEvento = new EventEmitter<TipoDeDato>();
2. Emisión del evento
this.nombreEvento.emit(valorAEnviar);
3. Escucha en el padre
<componente-hijo (nombreEvento)="manejarEvento($event)"></componente-hijo>
Ejemplo práctico: selector de producto
Veamos un ejemplo más completo con un componente que permite seleccionar productos:
import { Component, Output, EventEmitter, Input } from '@angular/core';
interface Producto {
id: number;
nombre: string;
precio: number;
}
@Component({
selector: 'app-producto-card',
template: `
<div class="producto-card">
<h3>{{ producto.nombre }}</h3>
<p>Precio: {{ producto.precio | currency:'EUR':'symbol':'1.2-2' }}</p>
<button (click)="seleccionar()" class="btn-seleccionar">
Seleccionar
</button>
<button (click)="eliminar()" class="btn-eliminar">
Eliminar
</button>
</div>
`
})
export class ProductoCardComponent {
@Input() producto!: Producto;
// Evento cuando se selecciona el producto
@Output() productoSeleccionado = new EventEmitter<Producto>();
// Evento cuando se elimina el producto
@Output() productoEliminado = new EventEmitter<number>();
seleccionar() {
this.productoSeleccionado.emit(this.producto);
}
eliminar() {
this.productoEliminado.emit(this.producto.id);
}
}
Uso en el componente padre
El componente padre escucha estos eventos como cualquier evento DOM:
@Component({
selector: 'app-catalogo',
template: `
<h2>Catálogo de productos</h2>
@for (producto of productos; track producto.id) {
<app-producto-card
[producto]="producto"
(productoSeleccionado)="onProductoSeleccionado($event)"
(productoEliminado)="onProductoEliminado($event)">
</app-producto-card>
}
@if (productoSeleccionado) {
<div class="seleccion">
<h3>Producto seleccionado:</h3>
<p>{{ productoSeleccionado.nombre }}</p>
</div>
}
`
})
export class CatalogoComponent {
productos: Producto[] = [
{ id: 1, nombre: 'Laptop', precio: 999 },
{ id: 2, nombre: 'Ratón', precio: 25 },
{ id: 3, nombre: 'Teclado', precio: 75 }
];
productoSeleccionado: Producto | null = null;
onProductoSeleccionado(producto: Producto) {
this.productoSeleccionado = producto;
console.log('Producto seleccionado:', producto);
}
onProductoEliminado(productoId: number) {
this.productos = this.productos.filter(p => p.id !== productoId);
console.log('Producto eliminado con ID:', productoId);
}
}
Tipado de eventos
Es una buena práctica tipar los EventEmitter para mayor seguridad y mejor experiencia de desarrollo:
// Evento que envía un número
@Output() numeroSeleccionado = new EventEmitter<number>();
// Evento que envía un string
@Output() textoIngresado = new EventEmitter<string>();
// Evento que envía un objeto personalizado
@Output() usuarioCreado = new EventEmitter<{ nombre: string; email: string }>();
// Evento que no envía datos (solo notifica)
@Output() accionCompletada = new EventEmitter<void>();
Convenciones de nomenclatura
Angular recomienda seguir estas convenciones para los nombres de eventos:
- Usar verbos en pasado:
productoSeleccionado
,datoGuardado
,formularioEnviado
- Ser descriptivos:
botonClickeado
es mejor queclick
- Evitar prefijos: no uses
on
como enonProductoSeleccionado
@Output vs eventos DOM nativos
Los @Output
funcionan exactamente igual que los eventos DOM nativos:
<!-- Eventos DOM nativos -->
<button (click)="manejarClick($event)">Click me</button>
<input (input)="manejarInput($event)">
<!-- Eventos personalizados con @Output -->
<app-contador (valorCambiado)="manejarCambio($event)"></app-contador>
<app-modal (modalCerrado)="manejarCierre($event)"></app-modal>
Alternativas modernas
Es importante mencionar que Angular 20 ofrece una alternativa moderna a @Output
tradicional llamada output()
, que forma parte del sistema de signals. Esta nueva API es más simple y está mejor integrada con el sistema de reactividad moderno de Angular.
// Nueva sintaxis con output() (se verá en el módulo de signals)
export class ComponenteModerno {
valorCambiado = output<number>(); // Más simple que @Output + EventEmitter
}
Sin embargo, @Output
con EventEmitter
sigue siendo completamente válido y ampliamente utilizado, especialmente en aplicaciones existentes. Es fundamental dominar esta sintaxis tradicional antes de avanzar a las APIs más modernas.
La comunicación mediante @Output
y EventEmitter
te permite crear componentes verdaderamente reutilizables que pueden adaptarse a diferentes contextos y necesidades, manteniendo un código limpio y bien estructurado.

Alan Sastre
Ingeniero de Software y formador, CEO en CertiDevs
Ingeniero de software especializado en Full Stack y en Inteligencia Artificial. Como CEO de CertiDevs, Angular es una de sus áreas de expertise. Con más de 15 años programando, 6K seguidores en LinkedIn y experiencia como formador, Alan se dedica a crear contenido educativo de calidad para desarrolladores de todos los niveles.
Más tutoriales de Angular
Explora más contenido relacionado con Angular y continúa aprendiendo con nuestros tutoriales gratuitos.
Aprendizajes de esta lección
- Comprender la necesidad de comunicación hijo-padre en Angular.
- Aprender a usar el decorador @Output para declarar eventos personalizados.
- Entender cómo emitir eventos con EventEmitter desde el componente hijo.
- Saber cómo escuchar y manejar estos eventos en el componente padre.
- Conocer buenas prácticas y convenciones para nombrar eventos personalizados.