What is event binding in Angular 8?

Event Emitter vs Subject en Angular: ¿Cuál Elegir?

hace 2 años

Valoración: 3.89 (1346 votos)

En el desarrollo de aplicaciones Angular, la gestión de la comunicación entre componentes es un aspecto fundamental. Angular nos proporciona herramientas poderosas para este propósito, incluyendo los EventEmitters y los Subjects de RxJS. Aunque a primera vista puedan parecer similares, sirven a propósitos distintos y son adecuados para diferentes escenarios. En este artículo, exploraremos las diferencias entre ellos, sus casos de uso y cuándo elegir uno sobre el otro, todo ello con ejemplos prácticos para una mejor comprensión.

Índice de Contenido

¿Qué es un EventEmitter en Angular?

Un EventEmitter es una clase proporcionada por Angular que se utiliza principalmente para la comunicación de componente a componente. Extiende el Subject de RxJS y está diseñado específicamente para emitir eventos dentro del contexto de las aplicaciones Angular.

How to emit an event from parent to child in Angular?
3 Answers 3 Use an event emitter in child and get the output inside parent component(s). On changing timezone, trigger a function to emit output. Bind the child event output to a function within parent component. Function to be triggered on event output detection.

Características Clave de EventEmitter:

  • Uso Principal en Comunicación Hijo-a-Padre: Típicamente se utiliza para enviar datos o eventos desde un componente hijo a su componente padre. Esto se logra a través del uso de @Output en el componente hijo.
  • Estrechamente Ligado a Angular: Los EventEmitters son parte integral de Angular y se utilizan comúnmente en combinación con las propiedades @Output para definir salidas de componentes.
  • Caso de Uso Limitado: Su propósito principal se centra en la comunicación dentro del contexto de los componentes Angular, especialmente en escenarios de interacción directa entre componentes padre e hijo. No se suele usar para comunicación entre servicios o para patrones de comunicación más complejos.
  • Síncrono y Sencillo: Los EventEmitters emiten valores de forma síncrona, lo que significa que el emisor y el receptor se ejecutan en el mismo hilo de ejecución. Esto los hace ideales para interacciones simples y directas entre componentes.

Ejemplo de Uso de EventEmitter

Imaginemos un escenario común: un componente hijo que contiene un botón y necesita notificar a su componente padre cuando este botón es clickeado, enviando además un mensaje. Veamos cómo se implementaría esto con un EventEmitter.

Componente Hijo (button-click.component.ts):

import { Component, EventEmitter, Output } from '@angular/core'; @Component({ selector: 'app-button-click', template: `<button (click)="onClick()">Click Me</button>` }) export class ButtonClickComponent { @Output() buttonClicked = new EventEmitter<string>(); onClick() { this.buttonClicked.emit('¡Botón clickeado!'); } } 

Componente Padre (app.component.ts):

import { Component } from '@angular/core'; @Component({ selector: 'app-root', template: `<app-button-click (buttonClicked)="handleButtonClick($event)"></app-button-click>` }) export class AppComponent { handleButtonClick(message: string) { console.log(message); // Imprime en consola: "¡Botón clickeado!" } } 

En este ejemplo, el EventEmitterbuttonClicked en el componente hijo emite un mensaje cuando se hace clic en el botón. El componente padre, a través de la vinculación de eventos en el template ((buttonClicked)="handleButtonClick($event)"), escucha este evento y ejecuta la función handleButtonClick, recibiendo el mensaje emitido.

¿Qué es un Subject en RxJS?

Un Subject es una clase fundamental en RxJS (Reactive Extensions for JavaScript) que actúa como un puente o pasarela entre los Observables y los Observers. En esencia, un Subject es tanto un Observable como un Observer. Esto significa que puede suscribirse a un Subject para recibir valores (como un Observable) y también puede emitir nuevos valores al Subject (como un Observer).

Características Clave de Subject:

  • Multicast: Un Subject es multicast, lo que significa que cuando un valor es emitido a través de un Subject, este valor se retransmite a todos los Observers que están suscritos a ese Subject. Esto contrasta con un Observable estándar, que es unicast (cada suscripción crea una nueva ejecución del Observable).
  • Versatilidad y Flexibilidad: Los Subjects son extremadamente versátiles y se pueden utilizar en una amplia variedad de escenarios. Son útiles para la comunicación entre componentes no relacionados directamente, para la gestión de estados en servicios, para la creación de streams de eventos personalizados y mucho más.
  • Parte de RxJS: Los Subjects son una parte central de la librería RxJS y se benefician de toda la potencia y flexibilidad de RxJS, como operadores para transformar, filtrar, combinar y gestionar flujos de datos asíncronos.
  • Tipos de Subjects: Existen diferentes tipos de Subjects en RxJS que ofrecen comportamientos ligeramente distintos, como BehaviorSubject, ReplaySubject y AsyncSubject. Cada uno de estos tipos se adapta a diferentes necesidades y escenarios.

Ejemplo de Uso de Subject (BehaviorSubject)

Consideremos un escenario donde necesitamos compartir información del usuario autenticado entre diferentes partes de la aplicación, incluyendo componentes y servicios. Un BehaviorSubject es una excelente opción para esto, ya que mantiene el último valor emitido y lo proporciona inmediatamente a cualquier nuevo suscriptor.

How to emit value from child to parent in Angular?
APPROACH: , Define an Output property in the child component: In the child component TypeScript file, create an Output property using Angular's EventEmitter. ... , Emit the event with data: Within the child component logic, when you want to pass data to the parent, emit an event using the EventEmitter's emit() method.

Servicio de Autenticación (auth.service.ts):

import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AuthService { private _currentUser = new BehaviorSubject(null); // Inicialmente sin usuario currentUser$ = this._currentUser.asObservable(); // Observable público para suscripciones constructor() { } login(user: any) { this._currentUser.next(user); // Emitir el usuario logueado } logout() { this._currentUser.next(null); // Emitir null al cerrar sesión } } 

Componente que muestra el nombre de usuario (user-profile.component.ts):

import { Component, OnInit, OnDestroy } from '@angular/core'; import { AuthService } from './auth.service'; import { Subscription } from 'rxjs'; @Component({ selector: 'app-user-profile', template: `<p>Usuario: <b>{{ userName }}</b></p>` }) export class UserProfileComponent implements OnInit, OnDestroy { userName: string = 'Invitado'; userSubscription: Subscription | undefined; constructor(private authService: AuthService) { } ngOnInit() { this.userSubscription = this.authService.currentUser$.subscribe(user => { this.userName = user ? user.name: 'Invitado'; }); } ngOnDestroy() { if (this.userSubscription) { this.userSubscription.unsubscribe(); } } } 

En este ejemplo, el BehaviorSubject_currentUser en el AuthService gestiona el estado del usuario autenticado. El componente UserProfileComponent se suscribe a currentUser$ (un Observable derivado del BehaviorSubject) para recibir actualizaciones del usuario actual y mostrar su nombre. Cuando el usuario inicia sesión (función login), el BehaviorSubject emite el nuevo usuario, y el componente UserProfileComponent actualiza la vista automáticamente.

Tabla Comparativa: EventEmitter vs. Subject

CaracterísticaEventEmitterSubject (RxJS)
Propósito PrincipalComunicación Hijo-a-Padre en Componentes AngularComunicación general, gestión de estados, streams de eventos
Uso Típico en AngularCon @Output para salidas de componentesEn servicios, comunicación entre componentes no relacionados, gestión de flujos asíncronos
Acoplamiento a AngularEstrechamente ligado, parte del framework AngularParte de RxJS, independiente del framework Angular
Tipo de ComunicaciónPrincipalmente Unidireccional (hijo a padre)Bidireccional y Multicast (un emisor a múltiples receptores)
Sincronía vs. AsincroníaSíncronoPuede ser usado tanto síncrona como asíncronamente (dependiendo del contexto de RxJS)
ComplejidadMás simple y directo para casos de uso específicosMás complejo y versátil, requiere comprensión de RxJS

¿Cuándo Usar EventEmitter vs. Subject?

La elección entre EventEmitter y Subject depende del escenario específico y las necesidades de comunicación en tu aplicación Angular.

  • Usar EventEmitter cuando:
    • Necesitas comunicar eventos o datos desde un componente hijo a su componente padre de manera directa y sencilla.
    • Estás trabajando con la comunicación estándar de componentes en Angular a través de @Output.
    • La comunicación es principalmente unidireccional (hijo a padre) y síncrona.
    • Buscas una solución simple y específica para la interacción entre componentes padre e hijo.
  • Usar Subject (o sus variantes como BehaviorSubject, ReplaySubject) cuando:
    • Necesitas una solución más flexible y poderosa para la gestión de flujos de datos y eventos.
    • La comunicación debe ser multicast (un emisor a múltiples receptores).
    • Necesitas gestionar el estado de la aplicación de forma reactiva, especialmente en servicios.
    • La comunicación es entre componentes no relacionados directamente o a través de servicios.
    • Necesitas utilizar operadores de RxJS para transformar, filtrar o combinar flujos de datos.
    • Estás construyendo patrones de comunicación más complejos y asíncronos.

Preguntas Frecuentes (FAQ)

¿Puedo usar un Subject en lugar de un EventEmitter para la comunicación hijo-a-padre?
Sí, técnicamente puedes usar un Subject en lugar de un EventEmitter para la comunicación hijo-a-padre. Sin embargo, EventEmitter está diseñado específicamente para este propósito en Angular y se integra mejor con el ciclo de vida de los componentes y el sistema de bindings de Angular. Usar EventEmitter en estos casos suele ser más idiomático y legible.
¿Es un EventEmitter un tipo de Subject?
Sí, un EventEmitter extiende la clase Subject de RxJS. Esto significa que hereda las funcionalidades básicas de un Subject, pero está adaptado y optimizado para el contexto de Angular, especialmente para la comunicación entre componentes.
¿Cuál es la diferencia entre un Subject y un BehaviorSubject?
Un Subject simple no almacena el último valor emitido. Los nuevos suscriptores solo reciben los valores que se emiten *después* de su suscripción. Un BehaviorSubject, en cambio, almacena el último valor emitido y lo proporciona inmediatamente a los nuevos suscriptores. También requiere un valor inicial al ser creado.
¿Cuándo debería usar un BehaviorSubject en lugar de un Subject?
Usa un BehaviorSubject cuando necesites que los nuevos suscriptores reciban el valor más reciente inmediatamente al suscribirse. Esto es útil en escenarios de gestión de estado donde necesitas mantener y compartir el estado actual entre diferentes partes de la aplicación, como el ejemplo del usuario autenticado.

Conclusión

En resumen, tanto EventEmitters como Subjects son herramientas valiosas para la comunicación en Angular, pero se adaptan a diferentes escenarios. Los EventEmitters son ideales para la comunicación directa y sencilla entre componentes padre e hijo, especialmente a través de @Output. Los Subjects, por otro lado, ofrecen una mayor flexibilidad y potencia para la gestión de flujos de datos más complejos, la comunicación entre componentes no relacionados y la gestión de estados en servicios. Comprender las diferencias y los casos de uso de cada uno te permitirá elegir la herramienta adecuada para cada situación, construyendo aplicaciones Angular más robustas y mantenibles.

Subir