Angular - Content projection



What is Content Projection in Angular?

Content projection is a technique available in the Angular component to include external content (from consumer of the component) along with layout and styles in the specific area of the component template.

Different Implementation of Content Projection

The different ways in which we can implement content projection are:

Single-Slot Content Projection

A component involving only one content projection is called single-slot content projection.

Example

Let us understand the content projection by creating the above explained component.

Step 1: Create a projectionSample application using the below command −

ng new projectionSample

Step 2: Navigate to project folder and create a new component with the name content-projection-sample:

cd projectSample

ng generate component content-projection-sample
CREATE src/app/content-projection-sample/content-projection-sample.component.html (41 bytes)
CREATE src/app/content-projection-sample/content-projection-sample.component.spec.ts (736 bytes)
CREATE src/app/content-projection-sample/content-projection-sample.component.ts (320 bytes)
CREATE src/app/content-projection-sample/content-projection-sample.component.css (0 bytes)

Step 3: Add <ng-content> tag in the template, i.e. content-projection-sample.component.html file as shown below −

<p>This is content from the component template</p>
   <ng-content></ng-content>
<p>This is another content from component template</p> 

Step 4: Use the content-projection-sample component in the app.component.html file as shown below −

<app-content-projection-sample>
   <p>This is external content</p>
</app-content-projection-sample>
<router-outlet></router-outlet>

Step 5: Now import the ContentProjectionSampleComponent inside the AppComponent.

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ContentProjectionSampleComponent } from './content-projection-sample/content-projection-sample.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, ContentProjectionSampleComponent],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent {
  title = 'projectionSample';
}

The output of the application is as shown below −

Application Output

Multi-Slot Content Projection

Angular allows multiple content to be projected in the component as well and it is called multi-slot content projection.

Example

Let us see how to use multiple content projections by modifying the above example.

Step 1: Add another <ng-content> along with selector attribute in the component template, content-projection-sample.component.html as shown below −

<p>This is content from the component template</p>
<ng-content></ng-content>
<p>This is another content from component template</p>
<ng-content select="[second]"></ng-content>

Step 2: Update the app component template, app.component.html as shown below −

<app-content-projection-sample>
   <p>This is external content</p>
   <p second>This is yet another external content</p>
</app-content-projection-sample>

<router-outlet></router-outlet>

Here, the value of selector attribute (second) set in the component template is used in the content to be projected.

Step 3: Now, run the application and check the output.

multi-slot content

Conditional content projection

Conditional content projection is projecting a content when certain condition is met. We can use ng-content to conditionally project the content. But it is not recommended since <ng-content> will be initialized even if the content is not going to be rendered. Instead, we can use <ng-template> to project the content safely since it will initialize the content only when it is going to be rendered.

Example

Let us create a working demo by updating our projectionSample application and learning the conditional projection in more detail.

Step 1: Create a directive, greet-content using angular CLI as shown below −

ng g directive directives/greet-content
CREATE src/app/directives/greet-content.directive.spec.ts (257 bytes)
CREATE src/app/directives/greet-content.directive.ts (184 bytes)

Step 2: Update the directive and get the template reference as shown below −

import { Directive, TemplateRef } from '@angular/core';

@Directive({
  selector: '[appGreetContent]',
  standalone: true
})
export class GreetContentDirective {

  constructor(public template: TemplateRef) { }

}

Here,

  • selector is the key to identify the directive

  • template is the reference object of type TemplateRef injected into the directive through constructor injection (dependency injection concept)

Step 3: Update the component, ContentProjectionSampleComponent to get the directive object and set the actual condition as shown below −

import { Component, ContentChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import { GreetContentDirective } from '../directives/greet-content.directive';

@Component({
  selector: 'app-content-projection-sample',
  standalone: true,
  imports: [CommonModule, GreetContentDirective],
  templateUrl: './content-projection-sample.component.html',
  styleUrls: ['./content-projection-sample.component.css']
})
export class ContentProjectionSampleComponent {
  show = true;
  @ContentChild(GreetContentDirective) greet!: GreetContentDirective;
}

Here,

  • show is the variable, which holds the deciding condition

  • @ContentChild is the decorator, which will be used to get the directive instance

Step 4: In the component's template, use ngIf for checking the condition, ng-container and ngTemplateOutlet to display the template (greet.template) in the components template as shown below −

<p>This is content from the component template</p>
<ng-content></ng-content>
<p>This is another content from component template</p>
<ng-content select="[second]"></ng-content>

<div *ngIf="show">
   <ng-container [ngTemplateOutlet]="greet.template"></ng-container>
</div>

Step 5: Finally, use the component and its conditional projection in the app component as shown below −

<app-content-projection-sample>
   <p>This is external content</p>
   <ng-container ngProjectAs="second">
      <p>This is yet another external content</p>
   </ng-container>
   
   <ng-template appGreetContent>
      Hi, I am coming from conditional template
   </ng-template>
</app-content-projection-sample>

<router-outlet></router-outlet>

Step 6: Now import the directive inside the AppComponent.

import { Component } from '@angular/core';
import { RouterOutlet } from '@angular/router';
import { ContentProjectionSampleComponent } from './content-projection-sample/content-projection-sample.component';
import { GreetContentDirective } from './directives/greet-content.directive';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [RouterOutlet, ContentProjectionSampleComponent, GreetContentDirective],
  templateUrl: './app.component.html',
  styleUrl: './app.component.css'
})
export class AppComponent {
  title = 'projectionSample';
}

Step 7: Run the application and check the output to find whether content is rendered through conditional projection concept or not:

conditional projection

Step 8: Update the condition, show in the component to false and check the output to find that the ng-template content is not rendered.

export class ContentProjectionSampleComponent {
   show = false;
   @ContentChild(GreetContentDirective) greet!: GreetContentDirective;
}
Component Template

Special Case: ngProjectAs Attribute

ngProjectAs is a special attribute used to project content in complex scenarios. One example is using ng-container to layout the template. As we know, ng-container does not render itself and out-render its child content, we need to use ngProjectAs attribute to project its content.

Let us change the above example to use ng-container and ngProjectAs attribute. Update the app component template, app.component.html as shown below −

<app-content-projection-sample>
   <p>This is external content</p>
   <ng-container ngProjectAs="second">
      <p>This is yet another external content</p>
   </ng-container>
</app-content-projection-sample>

<router-outlet></router-outlet>

Here, the value of selector attribute (second) set in the component template is used in the ng-container.

The output of the application is as shown below −

ngProjectAs
Advertisements