1

I'm creating a component dynamically and I need to add (click) handler with $event as a parameter at this dynamic component like we do this at HTML template <div (click)="clickHandler($event)">

const componentFactory = this.componentFactoryResolver.resolveComponentFactory(component);
const viewContainerRef = this.viewContainerRef.createComponent(componentFactory);

viewContainerRef.instance.message = componentData.message;

This click should handle EventEmitter($event)

How do I do this? Thanks for advance!

Angry Beaver
  • 415
  • 1
  • 6
  • 18
  • What do you mean by _"This click should handle `EventEmitter($event)`"_? Is there an `@Output()` variable in this dynamic component that should also be handled by the same event handler as the `(click)` event's? – ruth Jun 18 '21 at 12:56
  • Yes, the component has the needed @Output() inside – Angry Beaver Jun 18 '21 at 13:02
  • What do then mean by the _"add (click) handler"_ to the component? Do you wish to capture a mouse click over the entire component? – ruth Jun 18 '21 at 13:06
  • Yes. the component is a chat message and need to handle mouse click on it:
    – Angry Beaver Jun 18 '21 at 13:15

1 Answers1

1

The answers are already available here and here.

I'd combine them here with an adjustment from the second answer. Instead of the Angular Renderer, I'd use the RxJS fromEvent function to get the events. Additionally RxJS Subject + takeUntil is used to close open subscriptions. See here for more info.

Try the following

import { fromEvent, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';

export class AppComponent implements OnDestroy {
  closed$ = new Subject<any>();

  @ViewChild('container', { read: ViewContainerRef })
  container: ViewContainerRef;

  private _counter = 1;

  constructor(private componentFactoryResolver: ComponentFactoryResolver) {}

  add(): void {
    // create the component factory
    const componentFactory = this.componentFactoryResolver.resolveComponentFactory(
      DynamicComponent
    );

    // add the component to the view
    const viewContainerRef = this.container.createComponent(componentFactory);

    // pass some data to the component
    viewContainerRef.instance.index = this._counter++;

    // get `@Output` emitter from the component
    viewContainerRef.instance.emitter
      .pipe(takeUntil(this.closed$))
      .subscribe((event: any) => this.clickHandler(event));

    // add `click` event handler to the component
    fromEvent(viewContainerRef.location.nativeElement, 'click')
      .pipe(takeUntil(this.closed$))
      .subscribe((event: any) => this.clickHandler(event));
  }

  clickHandler(event?: any) {
    console.log(event);
  }

  ngOnDestroy() {
    this.closed$.next(); // <-- close open subscriptions
  }
}

Working example: Stackblitz (extended from here).

ruth
  • 29,535
  • 4
  • 30
  • 57