Reputation: 3698
I am going through this tutorial to comprehend angular 2's ng-content
. I want to capture event which is triggered on ng-content
. I have following component:
@Component({
moduleId: module.id,
selector: 'card',
template: `
<ng-content (click)="onClick($event)"></ng-content>
`
})
export class CardComponent {
onClick(){
console.log('clicked');
}
}
Here, as you can see I am setting a listener to the click
event. But for some reasons it is not triggering. It seems like the entire ng-content
tag is replaced. So to capture the event currently I am doing this:
template: `
<div (click)="onClick($event)">
<ng-content></ng-content>
</div>
`
Is there any better way to do this? cause I don't want to wrap my ng-content
into a div
to avoid styling issues. Thanks. Plnkr
Upvotes: 15
Views: 12586
Reputation: 508
You can use @ContentChild to capture the events of projected component.
Child:
@Component({
moduleId: module.id,
selector: 'card-child',
template: `
<div>Card Child component</div>
`
})
export class CardChildComponent {
@Output customEvent:EventEmitter = new EventEmitter()
}
Parent:
@Component({
moduleId: module.id,
selector: 'card',
template: `
<ng-content></ng-content>
`
})
export class CardComponent {
@ContentChild(CardChildComponent) childComp: CardChildComponent;
ngAfterContentInit() {
this.childComp.addEventListener("click", ()=>{console.log("clicked"});
//Below is handling of custom event
this.childComp.customEvent.subscribe(()=>{console.log("clicked"});
}
}
Below is how the component will be injected.
<card>
<card-child></card-child>
</card>
Upvotes: 5
Reputation: 1501
You can achieve pretty the same result by binding event listeners to the component element with host declaration.
import { Component, HostListener } from '@angular/core';
@Component({
selector: 'card',
template: `<ng-content></ng-content>`
})
export class ButtonComponent {
@HostListener('click', ['$event.target'])
onClick(target) {
console.log('Clicked on: ', target);
}
}
Upvotes: 8
Reputation: 18292
<ng-content>
is just a placeholder to transclude the contents inside a component's tags. Angular replaces it.
The only option to avoid using the DIV
solution, would be to create your own version of ng-content
.
Basically, you just create an empty component and, in the template, you only put a <ng-content>
tag. If you call that component AppContentComponent
(app-content), then you can, in your components,
<app-content (click)="onClick()">
<ng-content></ng-content>
</app-content>
Of course, this is a bit convoluted, and you end up wrapping your transcluded content into another tag (not a <div>
, but an <app-content>
), though, of course, initially you didn't mind the content being wrapped by an <ng-content>
so I suppose it might work for you.
Upvotes: 0