Content projection with ng-content is a feature that can help us when we building a configurable reusable component.
ng-content is a directive that we can use as a selector and this serves as a hook you can put in a component to mark the place for angular where it should add any content it findes between the opening and closing tag of the component.
<!--app.component.html-->
<my-demo1>
<p>This is a projected content
</my-demo1>
<!--demo1.component.html-->
<div>
<ng-content>
</div>
This feature is useful especially if you think about building reusable widgets, like a tab widget where each tab will have a content which comes from another source and which you don’t want to pass through property binding.
We can also use multiple projections, which will give us control how the contents will get projected by using the “select” attribute of ng-content. It takes an element selector to decide which content to project inside a particular ng-content.
<!--app.component.html-->
<my-demo2>
<h1>Multiple projections
<p>a great feature to help us create a reusable components
</my-demo2>
<!--demo2.component.html-->
<div>
<div>
<ng-content select="h1">
</div>
<div>
<ng-content select="p">
</div>
</div>
Sometimes we might want to access the element or directive from the content DOM and to be able to use that in the place that this content will be projected.
You can use @ContentChild decorator to get the first element or the directive matching the selector from the content DOM. If the content DOM changes, and a new child matches the selector, the property will be updated.
Notice that we use ContentChild decorator and not ViewChild decorator since this element is not part of the view, it’s part of the content,
<my-demo1>
<p #contentParagraph>This is a projected content
</my-demo1>
import { AfterContentInit,Component,ContentChild,ElementRef } from "@angular/core";
@Component({
selector: "my-demo1",
templateUrl: "./demo1.component.html"
})
export class Demo1Component implements AfterContentInit {
@ContentChild("contentParagraph", { static: true }) paragraph: ElementRef;
ngAfterContentInit() {
// display: This is a projected content
console.log(this.paragraph.nativeElement.innerText);
}
}