Search code examples
angularviewchildng-template

How to attach click handler to projected content element


I'm using content projection to put a button into a component.

<hello name="{{ name }}">
  <button #btn>Click Me</button>
</hello>

And the component:

@Component({
  selector: 'hello',
  template: `
  <h3>Hello {{name}}!</h3>
  <ng-content></ng-content>
  `
})

So far so good... but i now want to add a (click) event listener to that button and I want the handler to live in the component that receives the projected content.

I was hoping to do the following to access the native element and then add a click listener.

@ViewChild('btn') btn

Unfortunately, when i console log this.btn in ngAfterViewInit, I get an "undefined". And even if it did work, i figure there must be a more angular way to attach the listener than accessing the native element.

What's the best way to accomplish this?

stackblitz example: https://stackblitz.com/edit/angular-cj4bz1?file=src%2Fapp%2Fhello.component.ts


Solution

  • You can use @ContentChild or @ContentChildren which gives you access to projected children inside of your component:

    You can read more about it here along with similarities and differences with @ViewChild and @ViewChildren Content Child Docs

    After you get access to you Child/Children you can use something like rxjs and the From Event Operator to get a hold of the click event.

    fromEvent(this.mycontentchildelement, 'click').subscribe((event) => console.log('got clicked', event));