# Structural directives This guide looks at how Angular manipulates the DOM with **structural directives** and how you can write your own structural directives to do the same thing. Try the . {@a definition} ## What are structural directives? Structural directives are responsible for HTML layout. They shape or reshape the DOM's _structure_, typically by adding, removing, or manipulating elements. As with other directives, you apply a structural directive to a _host element_. The directive then does whatever it's supposed to do with that host element and its descendants. Structural directives are easy to recognize. An asterisk (*) precedes the directive attribute name as in this example. No brackets. No parentheses. Just `*ngIf` set to a string. You'll learn in this guide that the [asterisk (*) is a convenience notation](guide/structural-directives#asterisk) and the string is a [_microsyntax_](guide/structural-directives#microsyntax) rather than the usual [template expression](guide/template-syntax#template-expressions). Angular desugars this notation into a marked-up `` that surrounds the host element and its descendents. Each structural directive does something different with that template. Three of the common, built-in structural directives—[NgIf](guide/template-syntax#ngIf), [NgFor](guide/template-syntax#ngFor), and [NgSwitch...](guide/template-syntax#ngSwitch)—are described in the [_Template Syntax_](guide/template-syntax) guide and seen in samples throughout the Angular documentation. Here's an example of them in a template: This guide won't repeat how to _use_ them. But it does explain _how they work_ and how to [write your own](guide/structural-directives#unless) structural directive.
Directive spelling
Throughout this guide, you'll see a directive spelled in both _UpperCamelCase_ and _lowerCamelCase_. Already you've seen `NgIf` and `ngIf`. There's a reason. `NgIf` refers to the directive _class_; `ngIf` refers to the directive's _attribute name_. A directive _class_ is spelled in _UpperCamelCase_ (`NgIf`). A directive's _attribute name_ is spelled in _lowerCamelCase_ (`ngIf`). The guide refers to the directive _class_ when talking about its properties and what the directive does. The guide refers to the _attribute name_ when describing how you apply the directive to an element in the HTML template.
There are two other kinds of Angular directives, described extensively elsewhere: (1) components and (2) attribute directives. A *component* manages a region of HTML in the manner of a native HTML element. Technically it's a directive with a template. An [*attribute* directive](guide/attribute-directives) changes the appearance or behavior of an element, component, or another directive. For example, the built-in [`NgStyle`](guide/template-syntax#ngStyle) directive changes several element styles at the same time. You can apply many _attribute_ directives to one host element. You can [only apply one](guide/structural-directives#one-per-element) _structural_ directive to a host element.
{@a ngIf} ## NgIf case study `NgIf` is the simplest structural directive and the easiest to understand. It takes a boolean expression and makes an entire chunk of the DOM appear or disappear. The `ngIf` directive doesn't hide elements with CSS. It adds and removes them physically from the DOM. Confirm that fact using browser developer tools to inspect the DOM. The top paragraph is in the DOM. The bottom, disused paragraph is not; in its place is a comment about "bindings" (more about that [later](guide/structural-directives#asterisk)). When the condition is false, `NgIf` removes its host element from the DOM, detaches it from DOM events (the attachments that it made), detaches the component from Angular change detection, and destroys it. The component and DOM nodes can be garbage-collected and free up memory. ### Why *remove* rather than *hide*? A directive could hide the unwanted paragraph instead by setting its `display` style to `none`. While invisible, the element remains in the DOM. The difference between hiding and removing doesn't matter for a simple paragraph. It does matter when the host element is attached to a resource intensive component. Such a component's behavior continues even when hidden. The component stays attached to its DOM element. It keeps listening to events. Angular keeps checking for changes that could affect data bindings. Whatever the component was doing, it keeps doing. Although invisible, the component—and all of its descendant components—tie up resources. The performance and memory burden can be substantial, responsiveness can degrade, and the user sees nothing. On the positive side, showing the element again is quick. The component's previous state is preserved and ready to display. The component doesn't re-initialize—an operation that could be expensive. So hiding and showing is sometimes the right thing to do. But in the absence of a compelling reason to keep them around, your preference should be to remove DOM elements that the user can't see and recover the unused resources with a structural directive like `NgIf` . **These same considerations apply to every structural directive, whether built-in or custom.** Before applying a structural directive, you might want to pause for a moment to consider the consequences of adding and removing elements and of creating and destroying components. {@a asterisk} ## The asterisk (*) prefix Surely you noticed the asterisk (*) prefix to the directive name and wondered why it is necessary and what it does. Here is `*ngIf` displaying the hero's name if `hero` exists. The asterisk is "syntactic sugar" for something a bit more complicated. Internally, Angular translates the `*ngIf` _attribute_ into a `` _element_, wrapped around the host element, like this. * The `*ngIf` directive moved to the `` element where it became a property binding,`[ngIf]`. * The rest of the `
`, including its class attribute, moved inside the `` element. The first form is not actually rendered, only the finished product ends up in the DOM. Angular consumed the `` content during its actual rendering and replaced the `` with a diagnostic comment. The [`NgFor`](guide/structural-directives#ngFor) and [`NgSwitch...`](guide/structural-directives#ngSwitch) directives follow the same pattern. {@a ngFor} ## Inside _*ngFor_ Angular transforms the `*ngFor` in similar fashion from asterisk (*) syntax to `` _element_. Here's a full-featured application of `NgFor`, written both ways: This is manifestly more complicated than `ngIf` and rightly so. The `NgFor` directive has more features, both required and optional, than the `NgIf` shown in this guide. At minimum `NgFor` needs a looping variable (`let hero`) and a list (`heroes`). You enable these features in the string assigned to `ngFor`, which you write in Angular's [microsyntax](guide/structural-directives#microsyntax).
Everything _outside_ the `ngFor` string stays with the host element (the `
`) as it moves inside the ``. In this example, the `[ngClass]="odd"` stays on the `
`.
{@a microsyntax} ## Microsyntax The Angular microsyntax lets you configure a directive in a compact, friendly string. The microsyntax parser translates that string into attributes on the ``: * The `let` keyword declares a [_template input variable_](guide/structural-directives#template-input-variable) that you 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 microsyntax parser title-cases all directives and prefixes them with the directive's attribute name, such as `ngFor`. For example, the `ngFor` input properties, `of` and `trackBy`, become `ngForOf` and `ngForTrackBy`, respectively. That's how the directive learns that the list is `heroes` and the track-by function is `trackById`. * 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`. * The `let-i` and `let-odd` variables were defined as `let i=index` and `let odd=odd`. Angular sets them to the current value of the context's `index` and `odd` properties. * The context property for `let-hero` wasn't specified. Its intended source is 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. * The [`NgFor` API guide](api/common/NgForOf "API: NgFor") describes additional `NgFor` directive properties and context properties. * The `NgForOf` directive implements `NgFor`. Read more about additional `NgForOf` directive properties and context properties in the [NgForOf API reference](api/common/NgForOf). ### Writing your own structural directives These microsyntax mechanisms are also available to you when you write your own structural directives. For example, microsyntax in Angular allows you to write `
{{item}}
` instead of `
{{item}}
`. The following sections provide detailed information on constraints, grammar, and translation of microsyntax. ### Constraints Microsyntax must meet the following requirements: - It must be known ahead of time so that IDEs can parse it without knowing the underlying semantics of the directive or what directives are present. - It must translate to key-value attributes in the DOM. ### Grammar When you write your own structural directives, use the following grammar: ``` *:prefix="( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*" ``` The following tables describe each portion of the microsyntax grammar.
prefix HTML attribute key
key HTML attribute key
local local variable name used in the template
export value exported by the directive under a given name
expression standard Angular expression
keyExp = :key ":"? :expression ("as" :local)? ";"?
let = "let" :local "=" :export ";"?
as = :export "as" :local ";"?
### Translation A microsyntax is translated to the normal binding syntax as follows:
Microsyntax Translation
prefix and naked expression [prefix]="expression"
keyExp [prefixKey] "expression" (let-prefixKey="export")
Notice that the prefix is added to the key
let let-local="export"
### Microsyntax examples The following table demonstrates how Angular desugars microsyntax.
Microsyntax Desugared
*ngFor="let item of [1,2,3]" <ng-template ngFor let-item [ngForOf]="[1,2,3]">
*ngFor="let item of [1,2,3] as items; trackBy: myTrack; index as i" <ng-template ngFor let-item [ngForOf]="[1,2,3]" let-items="ngForOf" [ngForTrackBy]="myTrack" let-i="index">
*ngIf="exp" <ng-template [ngIf]="exp">
*ngIf="exp as value" <ng-template [ngIf]="exp" let-value="ngIf">
Studying the [source code for `NgIf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_if.ts "Source: NgIf") and [`NgForOf`](https://github.com/angular/angular/blob/master/packages/common/src/directives/ng_for_of.ts "Source: NgForOf") is a great way to learn more. {@a template-input-variable} {@a template-input-variables} ## Template input variable A _template input variable_ is a variable whose value you can reference _within_ a single instance of the template. There are several such variables in this example: `hero`, `i`, and `odd`. All are preceded by the keyword `let`. A _template input variable_ is **_not_** the same as a [template _reference_ variable](guide/template-syntax#ref-vars), neither _semantically_ nor _syntactically_. You declare a template _input_ variable using the `let` keyword (`let hero`). The variable's scope is limited to a _single instance_ of the repeated template. You can use the same variable name again in the definition of other structural directives. You declare a template _reference_ variable by prefixing the variable name with `#` (`#var`). A _reference_ variable refers to its attached element, component or directive. It can be accessed _anywhere_ in the _entire template_. Template _input_ and _reference_ variable names have their own namespaces. The `hero` in `let hero` is never the same variable as the `hero` declared as `#hero`. {@a one-per-element} ## One structural directive per host element Someday you'll want to repeat a block of HTML but only when a particular condition is true. You'll _try_ to put both an `*ngFor` and an `*ngIf` on the same host element. Angular won't let you. 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 descendents. When two directives lay claim to the same host element, which one takes precedence? Which should go first, 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`](guide/structural-directives#ngcontainer) so you don't have to introduce extra levels of HTML. {@a ngSwitch} ## Inside _NgSwitch_ directives The Angular _NgSwitch_ is actually a set of cooperating directives: `NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault`. Here's an example. The switch value assigned to `NgSwitch` (`hero.emotion`) determines which (if any) of the switch cases are displayed. `NgSwitch` itself is not a structural directive. It's an _attribute_ directive that controls the behavior of the other two switch directives. That's why you write `[ngSwitch]`, never `*ngSwitch`. `NgSwitchCase` and `NgSwitchDefault` _are_ structural directives. You attach them to elements using the asterisk (*) prefix notation. An `NgSwitchCase` displays its host element when its value matches the switch value. The `NgSwitchDefault` displays its host element when no sibling `NgSwitchCase` matches the switch value.
The element to which you apply a directive is its _host_ element. The `` is the host element for the happy `*ngSwitchCase`. The `` is the host element for the `*ngSwitchDefault`.
As with other structural directives, the `NgSwitchCase` and `NgSwitchDefault` can be desugared into the `` element form. {@a prefer-asterisk} ## Prefer the asterisk (*) syntax. The asterisk (*) syntax is more clear than the desugared form. Use [<ng-container>](guide/structural-directives#ng-container) when there's no single element to host the directive. While there's rarely a good reason to apply a structural directive in template _attribute_ or _element_ form, it's still important to know that Angular creates a `` and to understand how it works. You'll refer to the `` when you [write your own structural directive](guide/structural-directives#unless). {@a template} ## The *<ng-template>* The <ng-template> is an Angular element for rendering HTML. It is never displayed directly. In fact, before rendering the view, Angular _replaces_ the `` and its contents with a comment. If there is no structural directive and you merely wrap some elements in a ``, those elements disappear. That's the fate of the middle "Hip!" in the phrase "Hip! Hip! Hooray!". Angular erases the middle "Hip!", leaving the cheer a bit less enthusiastic. A structural directive puts a `` to work as you'll see when you [write your own structural directive](guide/structural-directives#unless). {@a ngcontainer} {@a ng-container} ## Group sibling elements with <ng-container> There's often a _root_ element that can and should host the structural directive. The list element (`
  • `) is a typical host element of an `NgFor` repeater. When there isn't a host element, you can usually wrap the content in a native HTML container element, such as a `
    `, and attach the directive to that wrapper. Introducing another container element—typically a `` or `
    `—to group the elements under a single _root_ is usually harmless. _Usually_ ... but not _always_. The grouping element may break the template appearance because CSS styles neither expect nor accommodate the new layout. For example, suppose you have the following paragraph layout. You also have a CSS style rule that happens to apply to a `` within a `

    `aragraph. The constructed paragraph renders strangely.

    The `p span` style, intended for use elsewhere, was inadvertently applied here. Another problem: some HTML elements require all immediate children to be of a specific type. For example, the `