Michi DeWitt | ng-conf | Oct 2020
This is first part of an ongoing series covering all the built-in Angular structural directives. This series is intended for new and experienced Angular developers.
Introduction
Welcome to Part 1 of our series on built-in structural directives in Angular applications! In this series, we are going to cover what structural directives are and provide a guide on how to use each of the built-in structural directives.
What are Structural Directives?
Structural directives allow a developer to manipulate the DOM in specific ways. This manipulation is done by adding, removing, or changing elements on the page. A structural directive is added as an attribute to an HTML element in a template. Only one structural directive can be added to each element and the directive should always be prefixed with an *
to make them easy to distinguish from other attributes on the element.
Angular comes with several built-in directives that can be used to control the DOM. Most directives work by manipulating the DOM based on values in the component. They are useful in dynamic applications where the page content often changes based on component values and/or user actions. It can be hard to have dynamic content with vanilla HTML and Javascript, but with Angular’s structural directives, it’s a breeze!
Note: We’ll only be focusing on the built-in directives in this series, but developers can also build their own custom structural directives as well.
How Do I Use Structural Directives?
To make use of a structural directive, the directive is simply added as an attribute on any element in an Angular template. The structural directive attribute is prefixed by the *
.
Example:
<div *someDirective class="my-class" (click)="doSomething()"></div>
In the snippet above, the structural directive someDirective
is easy to distinguish on the div
element because of the *
prefix.
A directive may also bind to properties in the component.
Example:
<div *someOtherDirective="someProperty" class="my-class"
(click)="doSomething()"></div>
In the snippet above, the structural directive someOtherDirective
is bound to the component property someProperty
.
In this post, we’ll be covering one of the most commonly used directives — ngIf
.
What is the NgIf Directive and How is it Used?
The ngIf
directive is used to conditionally add or remove elements from the DOM. This is much more powerful than simply showing and hiding elements because you are able to:
- Only initialize components when they are needed
- Destroy components when they are no longer needed
- Not add expensive components when they are not needed
The syntax of the ngIf
directive is very similar to a conditional if-statement in Javascript which makes it easy and intuitive for developers to use. (It is also almost identical to the ngIf
directive in AngularJS).
Here are some situations this directive is particularly useful for:
- You want to add/remove content based on the action of a user
- You want to add/remove content based on some configuration value
- You want to add/remove content based on one or more values in the component
Basic Usage:
<div *ngIf="someCondition">
I want to show this if someCondition is truthy!
</div>
The ngIf
directive is added as an attribute on any element you want to conditionally add to the DOM. The directive binds to a condition and the value of that condition is used to determine if the element is added or removed.
When the component is first initialized, the value of any ngIf
condition is checked and the following will occur:
- If the condition evaluates to
truthy
, the element is added to the DOM - If the condition evaluates to
falsy
, the element is not added to the DOM
Simple as that!
If the condition changes as the result of change detection, the element the Angular directive was applied to will be appropriately removed or added to the DOM based on the new conditional value.
Let’s highlight the most important part again because the power of the ngIf
directive can be subtle.
When the NgIf condition evaluates to
falsy
, the element is not hidden in the DOM. It is removed completely — or never added in the first place.
For a small piece of text in a page, this may seem inconsequential. But when combined with more expensive components, you can see large performance implications (both good and bad).
The condition for the ngIf
directive can either be bound directly to a property in the component.
Example:
*ngIf="someProperty"
Or the condition can be bound to a boolean expression.
Example:
*ngIf="someProperty !== undefined"
One reason the ngIf
directive is easy to use is because it maps closely to the if-statement Javascript syntax many Angular developers are already familiar with. You can mentally map the HTML syntax above to:
if (someCondition) {
// Execute the code in this block
}
Else Block
Often, you will want to display a different template if the condition in your ngIf
directive is falsy
. You may be tempted to add a second ngIf
directive that explicitly checks if the same condition is falsy
…
<div *ngIf="someCondition">
If someCondition is truthy, show this
</div>
<!-- Avoid! This is an anti-pattern. -->
<div *ngIf="!someCondition">
Otherwise I want to show this
</div>
But there is a better way!
<div *ngIf="someCondition; else otherBlock">
If someCondition is truthy, show this
</div>
<ng-template #otherBlock>
Otherwise I want to show this
</ng-template>
Like a traditional if-statement in Javascript, you can specify that a different template should be added in the case the condition in the ngIf
directive is falsy
.
But why is this better?
- First, this provides a clean, easy to understand logical flow in your template.
- This keeps your conditional logic in one place. With the anti-pattern shown above, if you change the
ngIf
condition in one location, you must change it in both. This is brittle and error-prone. - You can add the
ng-template
anywhere that makes sense in your HTML template. It does not need to be directly underneath thengIf
directive. This gives you more control over how you want to organize your template.
Again, conceptually, this is very similar to the if-else-statement syntax most Angular developers are already familiar with.
f (someCondition) {
// Execute this code block
} else {
// Execute this other block
}
Storing NgIf Value
It’s not uncommon to need to use the result of the ngIf
condition in multiple places in your template. This is very common when the ngIf
condition is bound to an Observable using the async
pipe.
One option is to add the condition in the all locations where the result of the ngIf
condition is needed…
<div *ngIf="tableData$ | async">
My Conditional Table
<my-table-component [data]="tableData$ | async"></my-table-component>
</div>
But again — there’s a better way!
<div *ngIf="tableData$ | async">
My Conditional Table
<my-table-component [data]="tableData$ | async"></my-table-component>
</div>
The as
syntax allows you to store the result of the condition as a local variable in the template. Now the value is available to easily re-use elsewhere in the template.
But why is this better?
- Again, this provides a clean, easy to understand logical flow in your application.
- Again, this keeps your conditional logic in one place.
- You do not need to create a second subscription to the
tableData$
Observable.
Summary
And that’s everything you need to know about the ngIf
directive!
Let’s go over the main points again:
🛠 Structural directives provide easy ways for Angular developers to control the DOM based on data in a component
🏗 Structural directives can be added to any element in an Angular template.
🎯 The ngIf
directive allows you to control the DOM based on a conditional value you bind directly to the directive
➕ When the ngIf
condition is truthy
the element will be added to the DOM
➖ When the ngIf
condition is falsy
the element will be remove from the DOM
💪 Use the else
and as
syntax to take full advantage of all the features provided by the Angular team
ng-conf: The Musical is coming
ng-conf: The Musical is a two-day conference from the ng-conf folks coming on April 22nd & 23rd, 2021. Check it out at ng-conf.org
Additional Thoughts & Resources
- Angular Structural Directive Docs: https://angular.io/guide/structural-directives#structural-directives
- Angular
*ngIf
Docs: https://angular.io/api/common/NgIf - In many examples in this blog, the only reason I added a
div
to the code was to attach a structural directive. In this case, it is often better to use<ng-container *ngIf="someCondition"></ng-container>
so an extra div is not added to the DOM. We’ll have more on this later in the series.
Top comments (0)