ng-content
Tags: angular, directives, typescript, contentprojection
Published: 2021-07-25 11:09:07

"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

######__links to other articles in this series are below__

#The ng-content

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

1. Single-slot content projection
2. Multiple-slot content projection
3. 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](https://dev.to/valoni01/ng-magical-directives-series-ngtemplateoutlet-2mp1)  


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.

#Multiple-Slot Content Projection

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>

```

#Summary 

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](https://dev.to/valoni01/ng-magical-directives-series-ng-container-2979)
Next: [*ngTemplateOutlet](https://dev.to/valoni01/ng-magical-directives-series-ngtemplateoutlet-2mp1)