Ng-Content & Content Projection In Angular
In this article, we will learn how to use ng-content to add external content (content projection) to the Template. We know how to transmit data from the parent component to the child component by using the @Input decorator. However, it is restricted to data. We can't use that technique to transmit content to the child component, which includes HTML elements, CSS, and so on. We'll need to employ content projection to accomplish this.
The HTML content is passed from the parent component to the child component using content projection. The template will be shown in a specific location by the child component. The ng-content element is used to identify a location in the child component's template. The selector attribute in ng-content also allows us to construct several slots. Each slot can receive distinct content from the parent.
What is ng-content
External or dynamic content can be inserted using the ng-content tag as a placeholder. The external content is passed from the parent component to the child component. When Angular parses the template, it adds the external content in the child component's template where ng-content appears.
Content projection can be used to make a reusable component. Components with comparable logic and layout that can be used in multiple places throughout the application.
Consider the case of a card component. It comprises three sections: a header, a footer, and a body. These categories will have a variety of content. We may use ng-content to send these parts from the parent component to the card component. This allows us to use the card component across the application.
Without ng-content
Let's develop a basic button component without ng-content first to see how content projection with ng-content works.
Create an Angular application from scratch. btn.component.ts is a new component. It's a straightforward component that shows a button with the caption Click Me.
import { Component } from '@angular/core'; @Component({ selector: 'app-btn', template: `<button> Click Me </button>` }) export class BtnComponent { }
Go to app.component.html and add the following code.
<h2>Simple Button Demo</h2> <app-btn></app-btn> <app-btn></app-btn>
ng-content Example
import { Component, Output, EventEmitter } from '@angular/core'; @Component({ selector: 'app-fancybtn', template: ` <button> <ng-content></ng-content> </button> ` }) export class FancyBtnComponent { }
Now, Open the app.component.html file and add the following code.
<h2>Button Demo With ng-content</h2> <app-fancybtn>Click Me</app-fancybtn> <app-fancybtn><b>Submit</b></app-fancybtn>
Events
<h2>Button with click event</h2> <app-fancybtn btnclicked="" click="" event=""><b>Submit</b></app-fancybtn>
Add the following code under the App.component.ts:
btnClicked($event) { console.log($event) alert('button clicked') }
Custom Events
@Output() someEvent:EventEmitter =new EventEmitter(); raiseSomeEvent() { this.someEvent.emit(args); }
component of the parent:
<app-fancybtn event="" osomething="" someevent=""><b>Submit</b></app-fancybtn>
Multiple Projections using ng-content
Example of the ng-content select attribute
import { Component } from '@angular/core'; @Component({ selector: 'app-card', template: ` <div class="card"> <div class="header"> <ng-content select="header"></ng-content> </div> <div class="content"> <ng-content select="content"></ng-content> </div> <div class="footer"> <ng-content select="footer"></ng-content> </div> </div> `, styles: [ ` .card { min- width: 280px; margin: 5px; float:left } .header { color: blue} ` ] }) export class CardComponent { }
<app-card> <header><h1>Angular</h1></header> <content>One framework. Mobile & desktop.</content> <footer><b>Super-powered by Google </b></footer> </app-card> <app-card> <header><h1 style="color: red;">React</h1></header> <content>A JavaScript library for building user interfaces</content> <footer><b>Facebook Open Source </b></footer> </app-card>
The select attribute is a CSS selector
import { Component } from '@angular/core'; @Component({ selector: 'card', template: ` <div class="card"> <div class="header"> <ng-content select=".header"></ng-content> </div> <div class="content"> <ng-content select=".content"></ng-content> </div> <div class="footer"> <ng-content select=".footer"></ng-content> </div> </div> `, styles: [ ` .card { width: 280px; margin: 5px; float:left; border-width:1px; border-style:solid ; } .header { color: blue} ` ] }) export class CardComponent {
We use it as well in the component.
<card> <div class="header"> <h1>Angular</h1> </div> <div class="content">One framework. Mobile & desktop.</div> <div class="footer"><b>Super-powered by Google </b></div> </card> <card> <div class="header"> <h1 style="color: red;">React</h1> </div> <div class="content">A JavaScript library for building user interfaces</div> <div class="footer"><b>Facebook Open Source </b></div> </card>
Similarly, as illustrated below, you can use the various CSS Selectors.
<ng-content select="custom-element"></ng-content> <ng-content select=".custom-class"></ng-content> <ng-content select="[custom-attribute]"></ng-content>
ng-content without selector catches all
<card> <div class="header"><h1>Typescript</h1></div> <div class="content">Typescript is a javascript for any scale</div> <div class="footer"><b>Microsoft </b></div> <p>This text will not be shown</p> </card>
We can use ng-content without any selection to fix the problem described previously. It will show all of the stuff that can't be projected into any of the other slots.
import { Component } from '@angular/core'; @Component({ selector: 'app-card', template: ` <div class="card"> <div class="header"> <ng-content select="header"></ng-content> </div> <div class="content"> <ng-content select="content"></ng-content> </div> <div class="footer"> <ng-content select="footer"></ng-content> </div> <ng-content></ng-content> </div> `, styles: [ ` .card { min- width: 280px; margin: 5px; float:left } .header { color: blue} ` ] }) export class CardComponent { }
ngProjectAs
<card> <ng-container> <div class="header"> <h1 style="color: red;">React</h1> </div> </ng-container> <div class="content">A JavaScript library for building user interfaces</div> <div class="footer"><b>Facebook Open Source </b></div> </card>
<card> <ng-container ngprojectas="header"> <div> <h1 style="color: red;">React</h1> </div> </ng-container> <div class="content">A JavaScript library for building user interfaces</div> <div class="footer"><b>Facebook Open Source </b></div> </card>