22
Ng-magical directives series (ng-content)
"Magic is just science that we do not understand yet"
...Arthur C. Clarke
This article is part of what I call the magical directives series. In this series, we will unravel the mystery behind some interesting Angular directives. Afterwards, we can add this little magic to our tool box. I call them magical directives because they play a very important role in building reusable components across our Angular applications.
Below are the directives that we will be looking at in this series.
- ng-template
- ng-container
- ng-content
- *ngTemplateOutlet
The ng-content
is used to create configurable components. If we use the ng-content
tag in our template, the inner content of the tags that define our component are then projected into this space.
//app-modal.html
<div>
<div class="header"> Amazing Header </div>
<div class="body">
<p> Hi Friends! How are you today </p>
</div>
<div class="footer">This is our footer</div>
<div>
The sample code above represents a modal. If there is a need to have this modal in multiple places in our application with different styles/content in the body, it means that we will have to create more modals for each of the use cases. This is not a problem for small apps. But imagine when you have to use similar modal in over 5 different places or more with dynamic content in the body. This is where the magical effects of ng-content
comes to our aid.
//app-modal.html
<div>
<div class="header"> Amazing Header </div>
<div class="body">
<ng-content> </ng-content>
</div>
<div class="footer">This is our footer</div>
<div>
In the sample code above, instead of hardcoding the content of the body, we used the <ng-content> </ng-content>
tag.
If other components wants to use the app-modal
component with a custom body, the components will project the content inside the app-modal
and the content projected will be positioned in the place where we have specified the ng-content
tag in the app-modal
as seen below.
//app-parent.html
<app-modal>
<div>
<h3> My body intro. </h3>
<p> The perfect paragraph </p>
</div>
</app-modal>
Instead of creating multiple modals for different use cases across our application, we are now able to create a single modal component that allows us to project whatever content we want in the body. This process is referred to as Content projection
. With this, we can build reusable components for a single project or a reusable component library for all our projects.
There are three types of content projection
- Single-slot content projection
- Multiple-slot content projection
- Conditional content projection
In order to keep our article dry, We will discuss the conditional content projection in the last session of this series *ngTemplateOutlet
The first example above covers the single-slot content projection, where we were only required to project a single dynamic content. What happens if the content of the header and footer are also dynamic?
//app-modal.html
<div>
<ng-content> </ng-content>
<div class="body">
<ng-content> </ng-content>
</div>
<ng-content> </ng-content>
<div>
In this case, Angular is going to scream Wooooooooh. Because Angular wouldn't know the exact place to project the content that we are trying to project. The multiple-slot content projection comes to our rescue.
The multiple-slot content projection is what allows us to project multiple dynamic content to our component. The ng-content
provides us with the select
attribute that allows us to specify an identifier for a specific ng-content
tag. Below are various ways in which we can achieve this with different selectors.
//app-modal.html
<div>
<ng-content select=".header"> </ng-content>
<div class="body">
<ng-content select="#body"> </ng-content>
</div>
<ng-content select="span"> </ng-content>
<div>
Here, we have specified unique selectors for each content that needs to be projected. anytime we want to reuse this modal component, we just need to ensure that we specify a class with the name header, a body with an id of body and also a span tag. When Angular sees this, it will automatically know where to position or project the content that you have projected as seen in the example below.
//app-parent.html
<app-modal>
<div class="header"> Our header </div>
<div id="body">
<h3> My body intro. </h3>
<p> The perfect paragraph </p>
</div>
<span> The footer</span>
</app-modal>
NOTE: If for some reasons there is an ng-content
tag without an identifier (select), it will automatically serves as a default projector for any content that has no identifier.
Other examples of multiple-slot content projection
//app-modal.html
<div>
<ng-content select="[slot=head]"></ng-content>
<ng-content select="[slot=body]"></ng-content>
<ng-content select="[slot=footer]"></ng-content>
</div>
//app-parent.html
<app-modal>
<div slot="head"> Our header </div>
<div slot="body"> Our body </div>
<div slot="footer"> Our footer </div>
</app-modal>
//app-modal.html
<div>
<ng-content select="[head]"></ng-content>
<ng-content select="[body]"></ng-content>
<ng-content select="[footer]"></ng-content>
</div>
//app-parent.html
<app-modal>
<div head> Our header </div>
<div body> Our body </div>
<div footer> Our footer </div>
</app-modal>
you can also use custom components tags/selectors.
//app-modal.html
<div>
<ng-content select="app-head"></ng-content>
<ng-content select="app-body"></ng-content>
<ng-content select="app-footer"></ng-content>
</div>
//app-parent.html
<app-modal>
<app-head> Our header </app-head>
<app-body> Our body </app-body>
<app-footer> Our footer </app-footer>
</app-modal>
With the ng-content
You can build your own reusable components without you worrying about the contents or the styles of the contents the users needs to project.
Previous: ng-container
Next: *ngTemplateOutlet
22