await Angular's EventEmitter

Viewed 3643

Is it possible to await till Angular EventEmitter emits, like it's possible to await ajax call (Angular 5 synchronous HTTP call)?

What I want to do is:

Having a Child component

@Component({
  template: '<button (click)="emit1()">emit</button>'
})
export class ChildComponent {
  @Output() dataChanged: EventEmitter<number> = new EventEmitter<number>(true);  // synchronous

  emit1(){
    this.dataChanged.emit(1)
  }
}

And a Parent component that dynamically creates a Child component

@Component()
export class ParentComponent {
  childComponentRef: ComponentRef<ChildComponent>

  constructor(private resolver: ComponentFactoryResolver, private vcRef: ViewContainerRef) {}

  openChild() {
    const factory = this.resolver.resolveComponentFactory(ChildComponent);
    this.childComponentRef = this.vcRef.createComponent(factory);
    await this.childComponentRef.instance.dataChanged.toPromise()
    alert('emited!')
  }

}

I want to (a)wait until the value is emitted from a Child component.

3 Answers

Angular EventEmitter is an interface extension of RxJS Subject. They are infact asynchronous and not synchronous like mentioned in the question. And so you need to subscribe to it listen to the emitted notifications.

openChild() {
  const factory = this.resolver.resolveComponentFactory(ChildComponent);
  this.childComponentRef = this.vcRef.createComponent(factory);
  this.childComponentRef.instance.dataChanged.subscribe(
    response => { alert('emited!') }
  );
}

You could pipe the dataChanged with first() to await the first value of the EventEmitter:

      openChild() {
        ...
        await this.childComponentRef.instance.dataChanged.pipe(first()).toPromise()
        alert('emited!')
      }

you can emit whenever you want from child component like

this.dataChanged.emit(yourData);

and in your parent component you can try catch that event using

this.childComponentRef.instance.dataChanged.then((res) => {
   console.log(res);
});
Related