En Angular, la interacción entre componentes es fundamental para construir aplicaciones dinámicas y modulares. Este tema cubre las diferentes formas en que los componentes pueden comunicarse entre sí, incluyendo la comunicación padre-hijo, hijo-padre y entre componentes hermanos.
Conceptos Clave
- Input y Output Decorators: Utilizados para la comunicación entre componentes padre e hijo.
- ViewChild y ContentChild: Permiten acceder a un componente hijo desde el componente padre.
- Servicios Compartidos: Facilitan la comunicación entre componentes que no tienen una relación directa de padre-hijo.
- EventEmitter: Utilizado para emitir eventos desde un componente hijo hacia su componente padre.
Comunicación Padre-Hijo
Input Decorator
El decorador @Input
permite que un componente hijo reciba datos de su componente padre.
Ejemplo
Componente Padre (parent.component.ts):
import { Component } from '@angular/core'; @Component({ selector: 'app-parent', template: `<app-child [childProperty]="parentProperty"></app-child>`, }) export class ParentComponent { parentProperty = 'Hello from Parent'; }
Componente Hijo (child.component.ts):
import { Component, Input } from '@angular/core'; @Component({ selector: 'app-child', template: `<p>{{ childProperty }}</p>`, }) export class ChildComponent { @Input() childProperty: string; }
Output Decorator y EventEmitter
El decorador @Output
y la clase EventEmitter
permiten que un componente hijo envíe datos a su componente padre.
Ejemplo
Componente Padre (parent.component.ts):
import { Component } from '@angular/core'; @Component({ selector: 'app-parent', template: `<app-child (childEvent)="handleChildEvent($event)"></app-child>`, }) export class ParentComponent { handleChildEvent(event: string) { console.log(event); } }
Componente Hijo (child.component.ts):
import { Component, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-child', template: `<button (click)="sendEvent()">Click me</button>`, }) export class ChildComponent { @Output() childEvent = new EventEmitter<string>(); sendEvent() { this.childEvent.emit('Hello from Child'); } }
Comunicación Hijo-Padre
ViewChild Decorator
El decorador @ViewChild
permite que un componente padre acceda a una instancia de un componente hijo.
Ejemplo
Componente Padre (parent.component.ts):
import { Component, AfterViewInit, ViewChild } from '@angular/core'; import { ChildComponent } from './child.component'; @Component({ selector: 'app-parent', template: `<app-child></app-child>`, }) export class ParentComponent implements AfterViewInit { @ViewChild(ChildComponent) childComponent: ChildComponent; ngAfterViewInit() { console.log(this.childComponent.childProperty); } }
Componente Hijo (child.component.ts):
import { Component } from '@angular/core'; @Component({ selector: 'app-child', template: `<p>Child Component</p>`, }) export class ChildComponent { childProperty = 'Hello from Child'; }
Comunicación entre Componentes Hermanos
Servicios Compartidos
Los servicios compartidos permiten la comunicación entre componentes que no tienen una relación directa de padre-hijo.
Ejemplo
Servicio (shared.service.ts):
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class SharedService { private messageSource = new Subject<string>(); currentMessage = this.messageSource.asObservable(); changeMessage(message: string) { this.messageSource.next(message); } }
Componente Hermano 1 (sibling1.component.ts):
import { Component } from '@angular/core'; import { SharedService } from './shared.service'; @Component({ selector: 'app-sibling1', template: `<button (click)="sendMessage()">Send Message</button>`, }) export class Sibling1Component { constructor(private sharedService: SharedService) {} sendMessage() { this.sharedService.changeMessage('Hello from Sibling 1'); } }
Componente Hermano 2 (sibling2.component.ts):
import { Component, OnInit } from '@angular/core'; import { SharedService } from './shared.service'; @Component({ selector: 'app-sibling2', template: `<p>{{ message }}</p>`, }) export class Sibling2Component implements OnInit { message: string; constructor(private sharedService: SharedService) {} ngOnInit() { this.sharedService.currentMessage.subscribe( (message) => (this.message = message) ); } }
Ejercicio Práctico
Ejercicio
- Crea un componente padre y un componente hijo.
- Utiliza
@Input
para pasar un mensaje del componente padre al componente hijo. - Utiliza
@Output
yEventEmitter
para enviar un mensaje del componente hijo al componente padre. - Crea dos componentes hermanos y un servicio compartido.
- Utiliza el servicio compartido para enviar un mensaje desde el primer componente hermano al segundo componente hermano.
Solución
Componente Padre (parent.component.ts):
import { Component } from '@angular/core'; @Component({ selector: 'app-parent', template: ` <app-child [childMessage]="parentMessage" (childEvent)="receiveMessage($event)"></app-child> <app-sibling1></app-sibling1> <app-sibling2></app-sibling2> `, }) export class ParentComponent { parentMessage = 'Message from Parent'; receiveMessage(event: string) { console.log('Received from child:', event); } }
Componente Hijo (child.component.ts):
import { Component, Input, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-child', template: ` <p>{{ childMessage }}</p> <button (click)="sendMessage()">Send to Parent</button> `, }) export class ChildComponent { @Input() childMessage: string; @Output() childEvent = new EventEmitter<string>(); sendMessage() { this.childEvent.emit('Message from Child'); } }
Servicio Compartido (shared.service.ts):
import { Injectable } from '@angular/core'; import { Subject } from 'rxjs'; @Injectable({ providedIn: 'root', }) export class SharedService { private messageSource = new Subject<string>(); currentMessage = this.messageSource.asObservable(); changeMessage(message: string) { this.messageSource.next(message); } }
Componente Hermano 1 (sibling1.component.ts):
import { Component } from '@angular/core'; import { SharedService } from './shared.service'; @Component({ selector: 'app-sibling1', template: `<button (click)="sendMessage()">Send to Sibling 2</button>`, }) export class Sibling1Component { constructor(private sharedService: SharedService) {} sendMessage() { this.sharedService.changeMessage('Message from Sibling 1'); } }
Componente Hermano 2 (sibling2.component.ts):
import { Component, OnInit } from '@angular/core'; import { SharedService } from './shared.service'; @Component({ selector: 'app-sibling2', template: `<p>{{ message }}</p>`, }) export class Sibling2Component implements OnInit { message: string; constructor(private sharedService: SharedService) {} ngOnInit() { this.sharedService.currentMessage.subscribe( (message) => (this.message = message) ); } }
Conclusión
La interacción entre componentes en Angular es esencial para construir aplicaciones complejas y modulares. A través de @Input
, @Output
, EventEmitter
, @ViewChild
, y servicios compartidos, los componentes pueden comunicarse de manera efectiva, permitiendo una mayor flexibilidad y reutilización del código. Con estos conceptos, estás preparado para manejar la comunicación entre componentes en tus aplicaciones Angular.
Curso de Angular
Módulo 1: Introducción a Angular
- ¿Qué es Angular?
- Configuración del Entorno de Desarrollo
- Arquitectura de Angular
- Primera Aplicación Angular
Módulo 2: Componentes de Angular
- Entendiendo los Componentes
- Creación de Componentes
- Plantillas de Componentes
- Estilos de Componentes
- Interacción entre Componentes
Módulo 3: Enlace de Datos y Directivas
- Interpolación y Enlace de Propiedades
- Enlace de Eventos
- Enlace de Datos Bidireccional
- Directivas Incorporadas
- Directivas Personalizadas
Módulo 4: Servicios e Inyección de Dependencias
- Introducción a los Servicios
- Creación y Uso de Servicios
- Inyección de Dependencias
- Inyectores Jerárquicos
Módulo 5: Enrutamiento y Navegación
Módulo 6: Formularios en Angular
- Formularios Basados en Plantillas
- Formularios Reactivos
- Validación de Formularios
- Formularios Dinámicos
Módulo 7: Cliente HTTP y Observables
- Introducción al Cliente HTTP
- Realizando Solicitudes HTTP
- Manejo de Respuestas HTTP
- Uso de Observables
- Manejo de Errores
Módulo 8: Gestión de Estado
- Introducción a la Gestión de Estado
- Uso de Servicios para la Gestión de Estado
- NgRx Store
- NgRx Effects
- NgRx Entity
Módulo 9: Pruebas en Angular
- Pruebas Unitarias
- Pruebas de Componentes
- Pruebas de Servicios
- Pruebas de Extremo a Extremo
- Simulación de Dependencias
Módulo 10: Conceptos Avanzados de Angular
- Angular Universal
- Optimización del Rendimiento
- Internacionalización (i18n)
- Pipes Personalizados
- Animaciones en Angular