DEV Community

Anubhab Mukherjee for This is Angular

Posted on

Content Projection in Angular

Today we will learn about a very important concept called Content Projection. It's very useful concept and helps to make an application dynamic.

Let's dive in by creating our playground first -
Lets create a component called my-cards and use it in the app.component.html file (Hint 😉 using the selector)
Image description


Now lets try out a simple exercise. Add the below code in the app.component.html file -

<app-my-cards>
    <span>
        This is some content in between the card selector!
    </span>
</app-my-cards>
Enter fullscreen mode Exit fullscreen mode

If you open the browser to check the output you will see the text you typed in between the selector i.e. This is some content in between the card selector! is not visible/ not getting displayed.

The output -
Image description

So the span element which is the child of the selector is the content and it's also the child element. So if we combine both the term we get content child. The span element is the content child.

Now as we saw earlier in the demo the content child is not getting displayed. So in order to display the content child we need to project it. Or in simple term we need to have a special placeholder (in the child component - MyCardsComponent) which will catch/ receive the value and display it.

This special placeholder is ng-content.

So now let's update the MyCardsComponent's template to have-

<ng-content></ng-content>
Enter fullscreen mode Exit fullscreen mode

and now you will see the below output -
Image description
So what exactly happens ?
The child content here in this case the span gets projected in the ng-content. So ng-content acts as a placeholder.

Now what if you need multiple placeholders? For example you will pass a content that would sit on the card-header another content as the card-body and another in the card-footer???
For that we need to use something called select - It is very powerful.
The select can accept a class, id, attribute or an element. Confused?

Lets see a quick example. Paste in the below code in the app.component.html file -

<app-my-cards>
    <header>Card Header</header>
    <span id='card-sub-header'>Card Sub Header</span>
    <div class="card-body">
        This is a card Body!!!
    </div>
    <footer title="card-footer">
        Card Footer.
    </footer>
</app-my-cards>
Enter fullscreen mode Exit fullscreen mode

And in the my-cards.component.html file i.e. MyCardsComponent's template file paste in the below code -

<ng-content select='header'></ng-content>
<ng-content select='#card-sub-header'></ng-content>
<ng-content select='.card-body'></ng-content>
<ng-content select='[title]'></ng-content>
Enter fullscreen mode Exit fullscreen mode

The output -
Image description

So the 1️⃣ first ng-content has a selector which matches an element/ tag - the header tag
2️⃣ Second ng-content selector matches an id card-sub-header
3️⃣ Third ng-content selector matches a class card-body
4️⃣ Fourth ng-content selector matches an attribute title

There can also be a scenario where instead of using header tag (in the above example) you need to use a div tag like below -

<app-my-cards>
    <div >Card Header</div>
    <span id='card-sub-header'>Card Sub Header</span>
    <div class="card-body">
        This is a card Body!!!
    </div>
    <footer title="card-footer">
        Card Footer.
    </footer>
</app-my-cards>
Enter fullscreen mode Exit fullscreen mode

Then the header will not work right? And suppose you don't have the option to change the card component also. Then what's the solution ???

ngProjectAs comes to the rescue!!!

Paste in the below code -

<app-my-cards>
    <div ngProjectAs='header'>Card Header</div>
    <span id='card-sub-header'>Card Sub Header</span>
    <div class="card-body">
        This is a card Body!!!
    </div>
    <footer title="card-footer">
        Card Footer.
    </footer>
</app-my-cards>
Enter fullscreen mode Exit fullscreen mode

Here you can see the first line is the div tag. And we have used ngProjectAs='header'. In this case Angular will consider the selector as header and the output will work as it is.

That's all for now.

Hope you enjoyed reading the post

If you liked it please like ❤️ share 💞 comment 🧡.

Coming up ContentChild and ContentChildren.
So stay tuned.

I will be tweeting more on Angular JavaScript TypeScript CSS tips and tricks.

So hope to see you there too 😃

Cheers 🍻
Happy Coding

Discussion (4)

Collapse
4502040 profile image
Nurbol

Thks for article. Perfect

Collapse
oliverdjbrown profile image
Oliver Brown

excellent article

Collapse
anubhab5 profile image
Anubhab Mukherjee Author

I am glad you liked it.

Collapse
kevinbarrientos profile image
Kevin Barrientos

What happens when the select matches multiple components?