Как стать автором
Обновить

Кастомный EventEmitter в Angular

image
Не секрет, что у новичков в Angular могут возникнуть проблемы с передачей данных между компонентами, потому что не всегда удается использовать Input и Output декораторы. Предлагаю вашему вниманию реализацию паттерна EventEmitter на Angular.

Для начала определим наш EventEmitter сервис, где разместим наш eventEmitterSubject$, принимающий поле action(тип события) и не обязательное поле payload(данные, которые мы хотим передать), для передачи событий и подписки на них.

import { Injectable } from '@angular/core';
import { Subject } from 'rxjs';

export type Actions = 'CREATE' | 'DELETE' | 'UPDATE';

@Injectable({
  providedIn: 'root'
})
export class EventEmitterService {

  eventEmitterSubject$ = new Subject<{ action: Actions, payload?: any }>();

}

Теперь можно определить и дочерний компонент, который будет вызывать события у родительского, через наш EventEmitter сервис, а конкретно вызывать метод next, у eventEmitterSubject$.

export class ChildComponent {

  constructor(private eventService: EventEmitterService) { }

  onCreate(data) {
    this.eventService
      .eventEmitterSubject$.next({action: 'CREATE', payload: data});
  }

  onDelete(id) {
    this.eventService
      .eventEmitterSubject$.next({action: 'DELETE', payload: { id }});
  }

}

И наконец, на эти события можно подписаться в родительском компоненте.
Обратите внимание, что можно подписываться, как на все события, так и на конкретные с помощью оператора filter, также надо не забыть отписатся от подписки при дестроее компонента, чтобы не было утечек памяти.

export class AppComponent implements OnInit, OnDestroy {

  // не забываем отписываться
  destroy$ = new Subject();

  constructor(private eventEmitterService: EventEmitterService) {}

  ngOnInit(): void {
    // подписка на все события
    this.eventEmitterService.eventEmitterSubject$
      .pipe(takeUntil(this.destroy$))
      .subscribe((event) => {
      switch (event.action) {
        case 'CREATE': {
          // do something
          break;
        }
        case 'DELETE': {
          // do something
          break;
        }
      }
    });

    // подписка на конкретное событие
    this.eventEmitterService.eventEmitterSubject$.pipe(
      takeUntil(this.destroy$),
      filter(event => event.action === 'CREATE')
    ).subscribe(({payload}) => {
      // do something
    });
  }

  ngOnDestroy() {
    // отписка
    this.destroy$.next();
    this.destroy$.complete();
  }

}

Надеюсь эта статься поможет начинающим разработчикам лучше понять, как могут взаимодействовать компоненты между собой с использованием cервисов и rxjs.
Теги:
Хабы:
Данная статья не подлежит комментированию, поскольку её автор ещё не является полноправным участником сообщества. Вы сможете связаться с автором только после того, как он получит приглашение от кого-либо из участников сообщества. До этого момента его username будет скрыт псевдонимом.