Angular Regime Series: Content Projection

Ahmed Khan
5 min readApr 19, 2020

--

If you have worked in Angular 1, then chances are you might already have heard of this concept by the name of transclusion. Content Proejction is not something developed by Angular team infact its a programming concept.

Introduction

Wikipedia defines it as:

In computer science, transclusion is the inclusion of part or all of an electronic document into one or more other documents by hypertext reference. Transclusion is usually performed when the referencing document is displayed, and is normally automatic and transparent to the end user. The result of transclusion is a single integrated document made of parts assembled dynamically from separate sources, possibly stored on different computers in disparate places.

Transclusion facilitates modular design which suggests reusablility to avoid the pitfalls of copy, pasting and hardcoding. So Content Project (aka transclusion) follows the same step. Store once, reuse everywhere which is also the DRY Principle( Dont Repeat Yourself).

Content Projection

A Content Project is simply a strategy that allows you to dynamically project the html content or components from one place to another. It is representated by <ng-content></ng-content> tags. You can think of it as sort of curly brace interpollation but on a huge scale.

Building Content Projection App

A Content Projection App we will be building in this article
what we will be worknig on this article

This is a Grading App we will be worknig on this article so lets get started.

When we start building our project, depending on the application size, you will definitly require to communicate between your components and whether or not you are moving towards state management systems, this is where you might run into a bit of hardcoded template code.

Directory Structure

|----AppRoute
| |--- CardComponent
| |--- CardlistComponent

So lets say you have a card component which contains all the logic for the cards that includes student name, percentage and then we have another component cardlist which will be displaying all the card details to the view. In order to communicate between the cardlist child component and card parent component, we will be using our Inputdecorators to pass data.

Content projection app with out ng-content

Now for the moment this is alright but lets say the client looks at the design and says i want to add a bit more stuff into the body like class no of students etc. Now you have more content to be added into the body in which case you will use Ng-content.
Ng-content simply projects all html , events and property bindings from parent component to your child component which is exactly what we need. Currently card is acting as smart component and cardlist as dumb which is only responsible to presentation while card is handling all the heavy logic. If you are not fimiliar which the concept of smart and dumb components, you can checkout this article i wrote on the topic.

So now in our card component, We have added another key of class in the infoCards object.

import { NgModule, Component, ViewChild } from '@angular/core';@Component({ selector: 'my-app', templateUrl: './app.component.html', styleUrls: [ './app.component.css' ],})export class AppComponent  {  infoCards = [   {name: 'Tommas Shelby', value: '50%',class:'2'},   {name: 'Oliver Queen', value: '100%',class:'3'},   {name: 'John Wick', value: '40%'  ,class:'5'},   {name: 'Bruce Wayne', value: '5%' ,class:'6'}  ];  contentCards = [   {name: 'Card Name'}  ];  ngOnInit() {  }}

Next our html file:

<div class="container">   <h2>Grade System:</h2>   <div class="info-card-wrapper col-12 no-gutters">     <div class="info-card-ctnr">        <app-cardlist 
[item]="item"
[index]="i"
*ngFor="let item of infoCards; let i= index;"
>
<h3>Class {{item.class}}</h3> </app-cardlist> </div> </div></div>

The code between the components will be projected to the child component and displayed where ever we have placed the Ng-content tag.

Card List component:

<div class="info-card box" 
[ngClass]="{'status-success': index === 1, 'status-warning': index === 2,'status-failure': index === 3 }">
<div class="header"> <img src="https://cdn.shortpixel.ai/client/q_glossy,ret_img,w_512/https://9huts.com/wp-content/uploads/2019/12/man_19-512.png" > </div> <div class="body"> <ng-content></ng-content> //==> here the html content will be displayed <p class="name">{{item.name}}</p> <p class="value">{{item.value}}</p> </div></div>

now if you run, everything will appear exactly as it did before along with the new dynamic template functionality.

With that we have successfully implemented Content Projection.

Multiple Ng-contents

Lets say we want to dispaly all the head and body html from the parent component. In this particular case, we can use multiple ng-contents in one component. The approach remains the same but how will ng-content know which html content will be placed where? Well there are multiple ways to do this. We can either use Decorators or class selectors to achieve this. Lets see how we can go about doing this. In our card component:

<div class="container">  <h2>Grade System:</h2>  <div class="info-card-wrapper col-12 no-gutters">    <div class="info-card-ctnr">       <app-cardlist 
[item]="item"
[index]="i"
*ngFor="let item of infoCards; let i= index;"
>
<img src="https://cdn.shortpixel.ai/client/q_glossy,ret_img,w_512/https://9huts.com/wp-content/uploads/2019/12/man_19-512.png" > <h3>Class {{item.class}}</h3> <p class="name">{{item.name}}</p> <p class="value">{{item.value}}</p> </app-cardlist> </div> </div></div>

We have moved all the html code from cardlist component to card component. Now in our cardlist component, we will add ng-content in place of html along with tag selectors to insert the data in ng-content by that particular tag.

Html file:

<div class="info-card box"[ngClass]="{'status-success': index === 1, 'status-warning': index === 2,'status-failure': index === 3 }">  <div class="header">     <ng-content select="img"></ng-content>  </div>  <div class="body">     <ng-content select="h3"></ng-content>  </div></div>

ok now if you run your app, you will see only the img and h3 tags content is displayed in the header and body.

Similary you can go on using Class selectors, attributes and decorators as well to display only the elements which includes them.

Conclusion

Content Projection is a great strategry that can prove make your app quite efficient by providing dynamic templates without affecting the components styling. I hope you find this article helpful, If you did, follow me on Medium and Twitter to get notification for more articles on Software Development and dont forget to hit the clap button. Finally! Thanks for reading and Happy coding!!!!!!

--

--

Ahmed Khan

Software Engineer 💻| Public Speaker 🎙️ | Writer ✍️. I speak JavaScript better than I speak English. Blockchain enthusiast.