in Angular

Content projection in Angular allows you to insert dynamic content from a parent component into a child component. It is commonly used to build reusable components where content can be provided by the parent. This avoids duplication of code and provides flexibility for the child component to display the content dynamically.

Key Points:

  • <ng-content> is used to project content from a parent component into a child component.
  • You can use named slots by using the select attribute to target specific content within the parent.
  • This allows the child component to be flexible and reusable without knowing the content that will be passed from the parent.

Example 1: Basic Content Projection

Let’s say you want to create a simple card component where content like the title and body is passed from the parent component to the child component.

Child Component (app-card)

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-card',
  template: `
    <div class="card">
      <div class="card-header">
        <ng-content></ng-content> <!-- Project content here -->
      </div>
      <div class="card-body">
        <ng-content></ng-content> <!-- Project content here -->
      </div>
    </div>
  `
})
export class CardComponent {}

Parent Component (app.component.html)

<app-card>
  <h5 class="card-title">Angular Course</h5>
  <p class="card-text">Learn Angular from scratch. Start with basic concepts and go up to advanced topics.</p>
</app-card>

In the above example, content from the parent (like the title and description) is passed inside the <app-card> tags and projected into the child component using <ng-content>.

Example 2: Using Named Slots for Content Projection

In some cases, you might have multiple sections of content in your child component and you want to project them into specific areas of the child template (e.g., a title, text, and a button). To achieve this, you can use named slots with the select attribute.

Child Component (app-course)

import { Component } from '@angular/core';
 
@Component({
  selector: 'app-course',
  template: `
    <div class="course-card">
      <h3 class="card-header">
        <ng-content select=".card-title"></ng-content> <!-- Project title content -->
      </h3>
      <p class="card-body">
        <ng-content select=".card-text"></ng-content> <!-- Project body content -->
      </p>
      <button class="card-footer">
        <ng-content select=".card-btn"></ng-content> <!-- Project button content -->
      </button>
    </div>
  `
})
export class CourseComponent {}

Parent Component (app.component.html)

<app-course>
  <h5 class="card-title">Angular Fundamentals</h5>
  <p class="card-text">Learn the basics of Angular, including components, directives, and services.</p>
  <button class="card-btn">Enroll Now</button>
</app-course>

Explanation:

  • In the app-course child component, we use multiple <ng-content> tags with the select attribute to project content into different sections (title, text, and button).
  • In the parent component (app.component.html), we assign content to the card-title, card-text, and card-btn classes, which will be projected into the appropriate places in the app-course component.

Benefits:

  • Avoids Duplication: Instead of creating multiple card components with similar HTML, you can create a single, reusable component (app-course) and project content dynamically from the parent.
  • Flexible and Reusable: This approach makes the component more flexible because the parent can decide what content to display inside the child component.

Conclusion:

Content projection in Angular allows for greater flexibility and reusability of components. It enables you to pass content from a parent to a child component dynamically, without the child component needing to know about the content structure in advance. Named slots give you even more control over where content should go inside the child component.


Implementation:

  1. Add Bootstrap to index.html
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>NgLab</title>
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-QWTKZyjpPEjISv5WaRU9OFeRpok6YctnYmDr5pNlyT2bRjXh0JMhjY6hW+ALEwIH" crossorigin="anonymous">
</head>
<body>
  <app-root></app-root>
</body>
</html>
  1. Create a component and add the following code to ng-content-demo-component.component.ts:
import { Component } from '@angular/core';
 
@Component({
  selector: 'app-ng-content-demo-component',
  standalone: false,
  
  templateUrl: './ng-content-demo-component.component.html',
  styleUrl: './ng-content-demo-component.component.css'
})
export class NgContentDemoComponentComponent {
 
}
  1. Create a component and add the following code to ng-content-demo-component.component.html:
<div class="card">
    <div class="card-body">
        <h5 class="card-title">
            <ng-content select=".card-title"></ng-content>
        </h5>
      <ng-content select=".card-text"></ng-content>
      <ng-content select=".card-link"></ng-content>
    </div> 
  </div>
  1. Now, display the result in app.component.html:
<!-- <h4>Hello,</h4> -->
 
<!-- <app-ng-content-demo-component></app-ng-content-demo-component>
<app-ng-template-demo-component></app-ng-template-demo-component> -->
 
 
<!-- ---------------------------Bad code -->
 
<!-- <div class="row">
  <div class="col-sm-4">
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">C</h5>
        <p class="card-text">A procedural programming language widely used for system programming and embedded systems, known for its efficiency and low-level memory manipulation.</p>
        <a href="#" class="btn btn-primary">Read More about C</a>
      </div>
    </div>
  </div>
  <div class="col-sm-4">
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">C++</h5>
        <p class="card-text">An extension of C that supports object-oriented programming (OOP) and other features like templates and exception handling.</p>
        <a href="#" class="btn btn-primary">Read More about C++</a>
      </div>
    </div>
  </div>
  <div class="col-sm-4">
    <div class="card">
      <div class="card-body">
        <h5 class="card-title">C#</h5>
        <p class="card-text">A modern, object-oriented programming language developed by Microsoft for building a wide range of applications, particularly on the .NET framework.</p>
        <a href="#" class="btn btn-primary">Read More about C#</a>
      </div>
    </div>
  </div>
</div> -->
 
<!-- ---------------------------Resuable code (we can use this anywhere in this project) -->
<div class="row">
  <div class="col-sm-4">
    <app-ng-content-demo-component>
      <div class="card-title">C</div>
      <div class="card-text">A procedural programming language widely used for system programming and embedded systems, known for its efficiency and low-level memory manipulation.</div>
      <a href="#" class="btn btn-primary card-link">Read More about C</a>
    </app-ng-content-demo-component>
  </div>
 
  <div class="col-sm-4">
    <app-ng-content-demo-component>
      <div class="card-title">C++</div>
      <div class="card-text">An extension of C that supports object-oriented programming (OOP) and other features like templates and exception handling.</div>
      <a href="#" class="btn btn-primary card-link">Read More about C++</a>
    </app-ng-content-demo-component>
  </div>
 
  <div class="col-sm-4">
    <app-ng-content-demo-component>
      <div class="card-title">C#</div>
      <div class="card-text">A modern, object-oriented programming language developed by Microsoft for building a wide range of applications, particularly on the .NET framework.</div>
      <a href="#" class="btn btn-primary card-link">Read More about C#</a>
    </app-ng-content-demo-component>
  </div>
</div>