Search code examples
javascriptangulartypescriptrxjseventemitter

Angular: EventEmitter's event wasn't successfully received via .subscribe


I'm trying to handle an event from NgLoopDirective within the method EV of NgDNDirective, by passing the EventEmitter object by reference and calling .subscribe() as described within the code below:

import { Directive, Input, ElementRef, Renderer2, EventEmitter } from '@angular/core';

@Directive({
  selector: '[ngDN]'
})
export class NgDNDirective {

  private dn: number = -1
  private ev: EventEmitter<void>;

  @Input() set ngDN(dn: number) {
    this.dn = dn
  }

  @Input() set EV(ref: {ev: EventEmitter<void>}) {
    console.log('waiting for ev')
    ref.ev.subscribe(() => {
      console.log('data-num:', this.dn)
      this.renderer.setAttribute(this.elRef, 'data-num', this.dn.toString())
    })
  }

  constructor(private elRef: ElementRef,
              private renderer: Renderer2) {}

}

@Directive({
  selector: '[ngLoop]'
})
export class NgLoopDirective {

  @Input() set ngLoop(iter_count: number) {
    this.container.clear()
    for (let i=0; i<iter_count; i++) {
      let ev: EventEmitter<void> = new EventEmitter<void>()
      let ref = {ev: ev}

      this.container.createEmbeddedView(this.template, {index: i, ev: ref})
      ev.emit()
    }
  }

  constructor(private template: TemplateRef<any>,
              private container: ViewContainerRef) {}

}

This is the used HTML code:

<ng-template [ngLoop]="10" let-i="index" let-ref="ev">
  <a href="#" [ngDN]="i" [EV]="ref"></a>
</ng-template>

When I debug the code under the console - I get only this message displayed:

waiting for ev

meaning that the event was not handled successfully as console.log('data-num:', this.dn) wasn't called.

What's supposed to cause the problem?


Solution

  • Angular runs change detection for NgDNDirective after you have emitted event.

    So either run change detection manually:

    const view = this.container.createEmbeddedView(this.template, {index: i, ev: ref});
    view.detectChanges();
    

    Plunker Example

    or use ReplaySubject instead of EventEmitter

    Plunker Example