Home > Software design >  Why is my Event Emitter not catching observables?
Why is my Event Emitter not catching observables?

Time:08-15

I created a ComponentMessengerService that uses an Event Emitter to allow for communication between two child components. The input component is supposed to send information to the output component via the use of an injected service in its constructor.

An Epic is just a custom model I have made.

Component messenger service source code:

@Injectable({
  providedIn: 'root'
})
export class ComponentMessengerService {
  epicNumberUpdated = new EventEmitter<string>();
  epicTitleUpdated = new EventEmitter<string>();
  epicListUpdated = new EventEmitter<Epic[]>();

  sendEpicNumber(epicNumber: string){
    this.epicNumberUpdated.emit(epicNumber);
  }

  sendEpicTitle(epicTitle: string){
    this.epicTitleUpdated.emit(epicTitle)
  }
  
  sendEpicList(epicList: Epic[]){
    this.epicListUpdated.emit(epicList)
  }
}

Output component source code:

export class OutputComponent implements OnInit {

  public epicTitle: string;
  public epicNumber: string;
  public epicList: Epic[] = [];

  constructor(private componentMessenger: ComponentMessengerService) {
    this.subscribeAll();
  }

  subscribeAll(){
    this.componentMessenger.epicListUpdated.subscribe(
      (epicList: Epic[]) => {
        this.epicList = epicList; })
    this.componentMessenger.epicTitleUpdated.subscribe(
      (epicTitle: string) => { this.epicTitle = epicTitle })
    this.componentMessenger.epicNumberUpdated.subscribe(
      (epicNumber: string) => {
        this.epicNumber = epicNumber; })
  }
}

The output's properties are data-bound to html elements and should be displayed once the component's properties have received the observables. I have debugged my application and can confirm that the input component is indeed sending the observables. Unfortunately, when I tried adding console.log() statements within the subscribeAll() to verify whether the event emitters were receiving any data, the line of code was never executed.

CodePudding user response:

did you try to call the subscribeAll() method in the ngOnInit ?

Difference between Constructor and ngOnInit

Update

I would solve the problem by using "Subject" instead of EventEmitter, I think EventEmitter need to work with @Output().

CodePudding user response:

We have Subject and BehaviorSubject for it.

@Injectable({
  providedIn: 'root'
})
export class ComponentMessengerService {
  epicNumberUpdated$ = new Subject<string>();
  epicTitleUpdated$ = new Subject<string>();
  epicListUpdated$ = new Subject<Epic[]>();

  sendEpicNumber(epicNumber: string): void {
    this.epicNumberUpdated$.next(epicNumber);
  }

  sendEpicTitle(epicTitle: string): void {
    this.epicTitleUpdated$.next(epicTitle)
  }
  
  sendEpicList(epicList: Epic[]): void {
    this.epicListUpdated$.next(epicList)
  }
}

And don't forget about the unsubscription from Observables, because you can have a memory leak.

export class OutputComponent implements OnInit, OnDestroy {
  epicTitle: string;
  epicNumber: string;
  epicList: Epic[] = [];

  private unsubscribe$ = new Subject<void>();

  constructor(private componentMessenger: ComponentMessengerService) {}

  ngOnInit(): void {
    initializeListeners();
  }

  ngOnDestroy(): void {
    this.unsubscribe$.next();
    this.unsubscribe$.complete();
  }

  private initializeListeners(): void {
    this.componentMessenger.epicListUpdated$
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe((epicList: Epic[]) => {
        this.epicList = epicList;
      });

    this.componentMessenger.epicTitleUpdated$
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe((epicTitle: string) => { 
        this.epicTitle = epicTitle;
      });

    this.componentMessenger.epicNumberUpdated$
      .pipe(takeUntil(this.unsubscribe$))
      .subscribe((epicNumber: string) => {
        this.epicNumber = epicNumber;
      });
  }
}
  • Related