Introduction
The angular framework is used to develop single-page applications. Its views are a combination of components, including the smallest one, like, for example, buttons up to whole pages. Content projection is a technology that allows us to project one component into another. This article is about how we can project and conditionally display parts of the view into other ones.
Ng-content
ng-content
is the mostly used angular feature to nest components. The easiest example would be:
<app-parent>
<p>I will be nested!</p>
</app-parent>
And template of AppParent
:
<div class="wrapper">
<ng-content></ng-content>
</div>
So the end result will be:
<app-parent>
<div class="wrapper"><p>I will be nested!</p></div>
</app-parent>
We can have more than one ng-content
element in our component, and we can distinguish their usage by adding a select
attribute to it with the query selector as a value.
Example usage:
<div class="wrapper"><ng-content></ng-content></div>
<div class="wrapper-2">
<ng-content select=".for-second-wrapper"></ng-content></div>
And then we can use it:
<app-parent>
<div class="wrapper"><p>I will be nested!</p></div>
<div class=".for-second-wrapper">
<p>I will be as next!</p>
</div>
</app-parent>
So the result will be:
<app-parent>
<div class="wrapper"><p>I will be nested!</p></div>
<div class="wrapper-2">
<div class=".for-second-wrapper">
<p>I will be as next!</p>
</div>
</div>
</app-parent>
NgIf, NgFor, NgSwitch
Sometimes we want to conditionally display one or another content. To do that, we can use the ngIf
directive. As a value, it expects a boolean set to true displays content and removes it from the DOM when the value is false. An example of usage can be:
<p *ngIf="isLoggedIn">I am logged in!</p>
And with the value:
isLoggedIn = true;
In Angular, a special HTML element can be used to keep content and display it in other places. That element is ng-template
. It can be used with the combination of ngIf
to display when the value is false. According to the above example:
<p *ngIf="isLoggedIn; else notLoggedIn">I am logged in!</p>
<ng-template #notLoggedIn>
<p>I am NOT logged in!</p>
</ng-template>
#name_of_element
like #notLoggedIn
is a template reference that can be used to select concrete HTML elements.
We can use the ngFor
directive to display the list of elements. The example:
<ul>
<li *ngFor="let user of users">{{user}}</li>
</ul>
And the ts:
users = ['John', 'Tom', 'Merry'];
It iterates through provided lists and puts each item under the variable. The result above will be:
<ul>
<li>John</li>
<li>Tom</li>
<li>Merry</li>
</ul>
To access the index of each element, we can use the index
variable:
<ul>
<li *ngFor="let user of users; let i = index">
{{user}}
</li>
</ul>
There are also boolean variables named odd
and even
, which can make a difference between the following items on the list.
We can use variables with the respective names first
and last
to check if the given item is first or last.
A combination of all the above could be:
<ul>
<li *ngFor="let user of users; let i = index; let first = first; let last = last; let odd = odd; let even = even">
{{user}}
<p *ngIf="first">I am first</p>
<p *ngIf="last">I am last</p>
<p *ngIf="odd">I am odd</p>
<p *ngIf="even">I am even</p>
</li>
</ul>
Similar to JavaScript, we can use switch
. In HTML, it is a combination of ngSwitch
and ngSwitchCase
, for example:
<div [ngSwitch]="userType">
<div *ngSwitchCase="'ADMIN'">
I am ADMIN
</div>
<div *ngSwitchCase="'MODERATOR'">
I am MODERATOR
</div>
<div *ngSwitchCase="'STANDARD'">
I am STANDARD
</div>
<div *ngSwitchDefault>
I am NOT KNOWN OR DEFAULT
</div>
</div>
And ts:
userType: 'ADMIN' | 'MODERATOR' | 'STANDARD' = 'STANDARD';
Summary
Angular has a robust content projection mechanism that allows us to combine rendered content combinations. You can visit the official documentation for details.
Top comments (1)
I regret Angular not having a fallback for the projected values
For example, If I want app-parent to display something if nothing is projected, this can be a bit cumbersome compared to other frameworks such as Svelte
Here’s to hoping it will be improved as part of the focus the dev team has on the component authoring format for the next versions! 🙌