You are on page 1of 1

Search 

 Structural directives

Structural directives
Structural directive
shorthand
This guide is about structural directives and provides conceptual information on how such directives
work, how Angular interprets their shorthand syntax, and how to add template guard properties to One structural
directive per
catch template type errors.
element

Structural directives are directives which change the DOM layout by adding and removing DOM Creating a structural
element. directive

Testing the
Angular provides a set of built-in structural directives (such as NgIf , NgFor , NgSwitch and others)
directive
which are commonly used in all Angular projects. For more information see Built-in directives.
Structural directive
syntax reference

For the example application that this page describes, see the live example / download
How Angular
example. translates
shorthand

Shorthand
examples

Structural directive shorthand


When structural directives are applied they generally are pre xed by an asterisk, * , such as *ngIf .

This convention is shorthand that Angular interprets and converts into a longer form. Angular
transforms the asterisk in front of a structural directive into an <ng-template> that surrounds the
host element and its descendants.

For example, let's take the following code which uses an *ngIf to displays the hero's name if hero
exists:

src/app/app.component.html (asterisk)

<div *ngIf="hero" class="name">{{hero.name}}</div> 

Angular creates an <ng-template> element and applies the *ngIf directive onto it where it
becomes a property binding in square brackets, [ngIf] . The rest of the <div> , including its class

attribute, is then moved inside the <ng-template> :

src/app/app.component.html (ngif-template)

<ng-template [ngIf]="hero"> 
<div class="name">{{hero.name}}</div>
</ng-template>

Note that Angular does not actually create a real <ng-template> element, but instead only renders
the <div> element.

<div _ngcontent-c0>Mr. Nice</div> 

The following example compares the shorthand use of the asterisk in *ngFor with the longhand
<ng-template> form:

src/app/app.component.html (inside-ngfor)

<div 
*ngFor="let hero of heroes; let i=index; let odd=odd; trackBy: trackById"
[class.odd]="odd">
({{i}}) {{hero.name}}
</div>

<ng-template ngFor let-hero [ngForOf]="heroes"


let-i="index" let-odd="odd" [ngForTrackBy]="trackById">
<div [class.odd]="odd">
({{i}}) {{hero.name}}
</div>
</ng-template>

Here, everything related to the ngFor structural directive is moved to the <ng-template> . All other

bindings and attributes on the element apply to the <div> element within the <ng-template> . Other
modi ers on the host element, in addition to the ngFor string, remain in place as the element moves
inside the <ng-template> . In this example, the [class.odd]="odd" stays on the <div> .

The let keyword declares a template input variable that you can reference within the template. The
input variables in this example are hero , i , and odd . The parser translates let hero , let i , and
let odd into variables named let-hero , let-i , and let-odd . The let-i and let-odd
variables become let i=index and let odd=odd . Angular sets i and odd to the current value of
the context's index and odd properties.

The parser applies PascalCase to all directives and pre xes them with the directive's attribute name,
such as ngFor. For example, the ngFor input properties, of and trackBy , map to ngForOf and

ngForTrackBy .

As the NgFor directive loops through the list, it sets and resets properties of its own context object.

These properties can include, but aren't limited to, index , odd , and a special property named
$implicit .

Angular sets let-hero to the value of the context's $implicit property, which NgFor has
initialized with the hero for the current iteration.

For more information, see the NgFor API and NgForOf API documentation.

Note that Angular's <ng-template> element de nes a template that doesn't render

anything by default, if you just wrap elements in an <ng-template> without applying a


structural directive those elements will not be rendered.

For more information, see the ng-template API documentation.

One structural directive per element


It's a quite common use-case to repeat a block of HTML but only when a particular condition is true.
An intuitive way to do that is to put both an *ngFor and an *ngIf on the same element. However,
since both *ngFor and *ngIf are structural directives, this would be treated as an error by the

compiler. You may apply only one structural directive to an element.

The reason is simplicity. Structural directives can do complex things with the host element and its

descendants.

When two directives lay claim to the same host element, which one should take precedence?

Which should go rst, the NgIf or the NgFor ? Can the NgIf cancel the effect of the NgFor ? If so
(and it seems like it should be so), how should Angular generalize the ability to cancel for other
structural directives?

There are no easy answers to these questions. Prohibiting multiple structural directives makes them
moot. There's an easy solution for this use case: put the *ngIf on a container element that wraps the

*ngFor element. One or both elements can be an <ng-container> so that no extra DOM elements
are generated.

Creating a structural directive


This section guides you through creating an UnlessDirective and how to set condition values.
The UnlessDirective does the opposite of NgIf , and condition values can be set to true or
false . NgIf displays the template content when the condition is true . UnlessDirective displays
the content when the condition is false .

Following is the UnlessDirective selector, appUnless , applied to the paragraph element. When
condition is false , the browser displays the sentence.

src/app/app.component.html (appUnless-1)

<p *appUnless="condition">Show this sentence unless the condition is true.</p>

1. Using the Angular CLI, run the following command, where unless is the name of the directive:

ng generate directive unless 

Angular creates the directive class and speci es the CSS selector, appUnless , that identi es the
directive in a template.

2. Import Input , TemplateRef , and ViewContainerRef .

src/app/unless.directive.ts (skeleton)

import { Directive, Input, TemplateRef, ViewContainerRef } from 


'@angular/core';

@Directive({ selector: '[appUnless]'})


export class UnlessDirective {
}

3. Inject TemplateRef and ViewContainerRef in the directive constructor as private variables.

src/app/unless.directive.ts (ctor)

constructor( 
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }

The UnlessDirective creates an embedded view from the Angular-generated <ng-


template> and inserts that view in a view container adjacent to the directive's original <p> host
element.
TemplateRef helps you get to the <ng-template> contents and ViewContainerRef
accesses the view container.

4. Add an appUnless @Input() property with a setter.

src/app/unless.directive.ts (set)

@Input() set appUnless(condition: boolean) { 


if (!condition && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
this.viewContainer.clear();
this.hasView = false;
}
}

Angular sets the appUnless property whenever the value of the condition changes.
If the condition is falsy and Angular hasn't created the view previously, the setter causes
the view container to create the embedded view from the template

If the condition is truthy and the view is currently displayed, the setter clears the container,
which disposes of the view

The complete directive is as follows:

src/app/unless.directive.ts (excerpt)

import { Directive, Input, TemplateRef, ViewContainerRef } from 


'@angular/core';

/**
* Add the template content to the DOM unless the condition is true.
*/
@Directive({ selector: '[appUnless]'})
export class UnlessDirective {
private hasView = false;

constructor(
private templateRef: TemplateRef<any>,
private viewContainer: ViewContainerRef) { }

@Input() set appUnless(condition: boolean) {


if (!condition && !this.hasView) {
this.viewContainer.createEmbeddedView(this.templateRef);
this.hasView = true;
} else if (condition && this.hasView) {
this.viewContainer.clear();
this.hasView = false;
}
}
}

Testing the directive


In this section, you'll update your application to test the UnlessDirective .

1. Add a condition set to false in the AppComponent .

src/app/app.component.ts (excerpt)

condition = false; 

2. Update the template to use the directive. Here, *appUnless is on two <p> tags with opposite
condition values, one true and one false .

src/app/app.component.html (appUnless)

<p *appUnless="condition" class="unless a"> 


(A) This paragraph is displayed because the condition is false.
</p>

<p *appUnless="!condition" class="unless b">


(B) Although the condition is true,
this paragraph is displayed because appUnless is set to false.
</p>

The asterisk is shorthand that marks appUnless as a structural directive. When the condition
is falsy, the top (A) paragraph appears and the bottom (B) paragraph disappears. When the
condition is truthy, the top (A) paragraph disappears and the bottom (B) paragraph appears.

3. To change and display the value of condition in the browser, add markup that displays the
status and a button.

src/app/app.component.html

<p> 
The condition is currently
<span [ngClass]="{ 'a': !condition, 'b': condition, 'unless': true }">
{{condition}}</span>.
<button
type="button"
(click)="condition = !condition"
[ngClass] = "{ 'a': condition, 'b': !condition }" >
Toggle condition to {{condition ? 'false' : 'true'}}
</button>
</p>

To verify that the directive works, click the button to change the value of condition .

The You can


d SHORTHAND HOW ANGULAR INTERPRETS THE SYNTAX
following improve
table
Improvingtemplate
provides type
shorthand
*ngFor="let <ng-template ngFor
template checking
item of let-item
examples: [1,2,3]" [ngForOf]=" type for
[1,2,3]"> checking custom
for directives

custom by adding
template
directives guard
*ngFor="let <ng-template ngFor properties
item of let-item to your
[1,2,3] as [ngForOf]=" directive
items; [1,2,3]"
de nition.
let-
trackBy: These
items="ngForOf"
myTrack;
properties
index as i"
[ngForTrackBy]="myTrack" help the
let-
Angular
i="index">
template
type

checker
nd
mistakes
in the
*ngIf="exp" <ng-template
template
[ngIf]="exp">
at
compile
time,
which can
avoid
*ngIf="exp <ng-template
[ngIf]="exp" runtime
as value"
let- errors.
value="ngIf"> These
properties
are as
follows:

RESOURCES HELP COMMUNITY LANGUAGES

About Stack Over ow Events Español


Resource Listing Join Discord Meetups 简体中文版
Press Kit Gitter Twitter 正體中文版

Blog Report Issues GitHub 日本語版


Usage Analytics Code of Conduct Contribute 한국어
Complete language list

Super-powered by Google ©2010-2022.

Code licensed under an MIT-style License. Documentation licensed under CC BY 4.0.

Version 13.3.10-local+sha.123782bfb6.

You might also like