From 6c783c7fcb2fd5401aab8d861a7e71839e5eb0bf Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Wed, 2 Dec 2020 12:48:25 -0500 Subject: [PATCH] docs: rewrite structural-directives.md (#40015) PR Close #40015 --- .../src/app/app.component.css | 2 - .../src/app/app.component.html | 26 +- .../src/app/app.component.ts | 3 +- aio/content/guide/ajs-quick-reference.md | 2 +- aio/content/guide/architecture-components.md | 4 +- aio/content/guide/built-in-directives.md | 14 +- aio/content/guide/example-apps-list.md | 2 +- aio/content/guide/glossary.md | 6 + aio/content/guide/interpolation.md | 2 +- aio/content/guide/structural-directives.md | 912 +++--------------- .../guide/template-reference-variables.md | 20 +- aio/content/guide/template-statements.md | 2 +- .../structural-directives/hero-div-in-dom.png | Bin 3537 -> 0 bytes packages/common/src/directives/ng_for_of.ts | 8 +- packages/common/src/directives/ng_if.ts | 4 +- packages/language-service/src/completions.ts | 2 +- 16 files changed, 194 insertions(+), 815 deletions(-) delete mode 100644 aio/content/images/guide/structural-directives/hero-div-in-dom.png diff --git a/aio/content/examples/structural-directives/src/app/app.component.css b/aio/content/examples/structural-directives/src/app/app.component.css index a3ed305907..b309e8bcf3 100644 --- a/aio/content/examples/structural-directives/src/app/app.component.css +++ b/aio/content/examples/structural-directives/src/app/app.component.css @@ -42,9 +42,7 @@ td, th { vertical-align: top; } -/* #docregion p-span */ p span { color: red; font-size: 70%; } -/* #enddocregion p-span */ .unless { border: 2px solid; diff --git a/aio/content/examples/structural-directives/src/app/app.component.html b/aio/content/examples/structural-directives/src/app/app.component.html index 00aa52ac2b..9fd74b2098 100644 --- a/aio/content/examples/structural-directives/src/app/app.component.html +++ b/aio/content/examples/structural-directives/src/app/app.component.html @@ -5,27 +5,21 @@

Conditional display of hero

- +
{{hero.name}}
- +

List of heroes

- - -

NgIf

-

Expression is true and ngIf is true. This paragraph is in the DOM. @@ -34,9 +28,7 @@ Expression is false and ngIf is false. This paragraph is not in the DOM.

- -

Expression sets display to "block". This paragraph is visible. @@ -45,7 +37,6 @@ Expression sets display to "none". This paragraph is hidden but still in the DOM.

-

NgIf with template

<ng-template> element

@@ -72,7 +63,7 @@ and continued on my way.

- +

I turned the corner @@ -80,10 +71,9 @@ and continued on my way.

-

<select> with <span>

- +
Pick your favorite hero () @@ -95,7 +85,6 @@ -

<select> with <ng-container>

@@ -148,17 +137,14 @@

NgSwitch

-
-

NgSwitch with <ng-template>

-
@@ -173,7 +159,6 @@
-
@@ -189,6 +174,7 @@

UnlessDirective

+

The condition is currently {{condition}}. @@ -198,6 +184,8 @@ Toggle condition to {{condition ? 'false' : 'true'}}

+ +

(A) This paragraph is displayed because the condition is false. diff --git a/aio/content/examples/structural-directives/src/app/app.component.ts b/aio/content/examples/structural-directives/src/app/app.component.ts index 68771063c3..c30efc576a 100644 --- a/aio/content/examples/structural-directives/src/app/app.component.ts +++ b/aio/content/examples/structural-directives/src/app/app.component.ts @@ -10,8 +10,9 @@ import { Hero, heroes } from './hero'; export class AppComponent { heroes = heroes; hero = this.heroes[0]; - + // #docregion condition condition = false; + // #enddocregion condition logs: string[] = []; showSad = true; status = 'ready'; diff --git a/aio/content/guide/ajs-quick-reference.md b/aio/content/guide/ajs-quick-reference.md index ebfb822779..c8dfb3ac10 100644 --- a/aio/content/guide/ajs-quick-reference.md +++ b/aio/content/guide/ajs-quick-reference.md @@ -140,7 +140,7 @@ The following table lists some of the key AngularJS template features with their Angular has true template input variables that are explicitly defined using the `let` keyword. - For more information, see the [Template input variables](guide/structural-directives#template-input-variable) section of [Structural Directives](guide/structural-directives). + For more information, see the [Structural directive shorthand](guide/structural-directives#shorthand) section of [Structural Directives](guide/structural-directives). diff --git a/aio/content/guide/architecture-components.md b/aio/content/guide/architecture-components.md index 5e3606e761..a264cceb86 100644 --- a/aio/content/guide/architecture-components.md +++ b/aio/content/guide/architecture-components.md @@ -166,8 +166,8 @@ The example template uses two built-in structural directives to add application -* [`*ngFor`](guide/structural-directives#inside-ngfor) is an iterative; it tells Angular to stamp out one `

  • ` per hero in the `heroes` list. -* [`*ngIf`](guide/structural-directives#ngif-case-study) is a conditional; it includes the `HeroDetail` component only if a selected hero exists. +* [`*ngFor`](guide/built-in-directives#ngFor) is an iterative; it tells Angular to stamp out one `
  • ` per hero in the `heroes` list. +* [`*ngIf`](guide/built-in-directives#ngIf) is a conditional; it includes the `HeroDetail` component only if a selected hero exists. #### Attribute directives diff --git a/aio/content/guide/built-in-directives.md b/aio/content/guide/built-in-directives.md index 901eeea7db..d0ca688f22 100644 --- a/aio/content/guide/built-in-directives.md +++ b/aio/content/guide/built-in-directives.md @@ -198,7 +198,7 @@ The string `"let item of items"` instructs Angular to do the following: * Translate `"let item of items"` into an `` around the host element * Repeat the `` for each `item` in the list -For more information see the [`` section](guide/structural-directives#the-ng-template) of [Structural directives](guide/structural-directives). +For more information see the [Structural directive shorthand](guide/structural-directives#shorthand) section of [Structural directives](guide/structural-directives). ### Repeating a component view To repeat a component element, apply `*ngFor` to the selector. @@ -215,7 +215,7 @@ The following example references `item` first in an interpolation and then passe -For more information about template input variables, see [Structural Directives](guide/structural-directives#template-input-variable). +For more information about template input variables, see [Structural directive shorthand](guide/structural-directives#shorthand). ### Getting the `index` of `*ngFor` @@ -228,8 +228,12 @@ The following example gets the `index` in a variable named `i` and displays it w The index property of the `NgFor` directive context returns the zero-based index of the item in each iteration. -{@a one-per-element} +Angular translates this instruction into an `` around the host element, +then uses this template repeatedly to create a new set of elements and bindings for each `item` +in the list. +For more information about shorthand, see the [Structural Directives](guide/structural-directives#shorthand) guide. +{@a one-per-element} ## Repeating elements when a condition is true To repeat a block of HTML when a particular condition is true, put the `*ngIf` on a container element that wraps an `*ngFor` element. @@ -278,7 +282,7 @@ They do not have special access to any private APIs that other directives can't The Angular `` is a grouping element that doesn't interfere with styles or layout because Angular doesn't put it in the DOM. -You can use [``](guide/structural-directives#ngcontainer) when there's no single element to host the directive. +You can use `` when there's no single element to host the directive. Here's a conditional paragraph using ``. @@ -339,8 +343,6 @@ For example, you could replace the `` switch case with a `
    ` -
    - ## What's next For information on how to build your own custom directives, see [Attribute Directives](guide/attribute-directives) and [Structural Directives](guide/structural-directives). diff --git a/aio/content/guide/example-apps-list.md b/aio/content/guide/example-apps-list.md index f3b88495bf..1cab4c8eaf 100644 --- a/aio/content/guide/example-apps-list.md +++ b/aio/content/guide/example-apps-list.md @@ -180,7 +180,7 @@ For more information, see [Template reference variables](guide/template-referenc Demonstrates ``. -For more information, see the [ngtemplate section](guide/structural-directives#ngcontainer) of [Structural directives](guide/structural-directives) . +For more information, see the [ng-container section](guide/built-in-directives#ngcontainer) of [Built-in directives](guide/structural-directives) . ### Pipes diff --git a/aio/content/guide/glossary.md b/aio/content/guide/glossary.md index 48583162f9..b154873562 100644 --- a/aio/content/guide/glossary.md +++ b/aio/content/guide/glossary.md @@ -340,6 +340,12 @@ Angular supplies a number of built-in directives that begin with the `ng` prefix You can also create new directives to implement your own functionality. You associate a *selector* (an HTML tag such as ``) with a custom directive, thereby extending the [template syntax](guide/template-syntax) that you can use in your apps. +**UpperCamelCase**, such as `NgIf`, refers to a directive class. +You can use **UpperCamelCase** when describing properties and directive behavior. + +**lowerCamelCase**, such as `ngIf` refers to a directive's attribute name. +You can use **lowerCamelCase** when describing how to apply the directive to an element in the HTML template. + {@a dom} ## domain-specific language (DSL) diff --git a/aio/content/guide/interpolation.md b/aio/content/guide/interpolation.md index 879aa1cfd9..7e5098655b 100644 --- a/aio/content/guide/interpolation.md +++ b/aio/content/guide/interpolation.md @@ -86,7 +86,7 @@ In the following snippet, the expression `recommended` and the expression `itemI -An expression can also refer to properties of the _template's_ context such as a [template input variable](guide/structural-directives#template-input-variables) or a [template reference variable](guide/template-reference-variables). +An expression can also refer to properties of the _template's_ context such as a [template input variable](guide/structural-directives#shorthand) or a [template reference variable](guide/template-reference-variables). The following example uses a template input variable of `customer`. diff --git a/aio/content/guide/structural-directives.md b/aio/content/guide/structural-directives.md index 5c2a4c5b1f..ea646e0d4b 100644 --- a/aio/content/guide/structural-directives.md +++ b/aio/content/guide/structural-directives.md @@ -1,330 +1,171 @@ -# 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/interpolation#template-expressions). -Angular desugars this notation into a marked-up `` that surrounds the -host element and its descendants. -Each structural directive does something different with that template. - -Three of the common, built-in structural directives—[NgIf](guide/built-in-directives#ngIf), -[NgFor](guide/built-in-directives#ngFor), and [NgSwitch...](guide/built-in-directives#ngSwitch)—are -described in the [Built-in directives](guide/built-in-directives) 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. - - -
    - +# Writing structural directives +This topic demonstrates how to create a structural directive and provides conceptual information on how directives work, how Angular interprets shorthand, and how to add template guard properties to catch template type errors.
    - - -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/built-in-directives#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. - +For the example app that this page describes, see the .
    +For more information on Angular's built-in structural directives, such as `NgIf`, `NgFor`, and `NgSwitch`, see [Built-in directives](guide/built-in-directives). + +{@a unless} + +## 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 `true`, the browser displays the sentence. + + + +1. Using the Angular CLI, run the following command, where `unless` is the name of the directive: + + ```bash + + ng generate directive unless + + ``` + + Angular creates the directive class and specifies the CSS selector, `appUnless`, that identifies the directive in a template. + +1. Import `Input`, `TemplateRef`, and `ViewContainerRef`. + + + +1. Inject `TemplateRef` and `ViewContainerRef` in the directive constructor as private variables. + + + + The `UnlessDirective` creates an [embedded view](api/core/EmbeddedViewRef "API: EmbeddedViewRef") from the Angular-generated `` and inserts that view in a [view container](api/core/ViewContainerRef "API: ViewContainerRef") adjacent to the directive's original `

    ` host element. + + [`TemplateRef`](api/core/TemplateRef "API: TemplateRef") helps you get to the `` contents and [`ViewContainerRef`](api/core/ViewContainerRef "API: ViewContainerRef") accesses the view container. + +1. Add an `appUnless` `@Input()` property with a setter. + + + + 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: + + + +### 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`. + + + +1. Update the template to use the directive. + Here, `*appUnless` is on two `

    ` tags with opposite `condition` values, one `true` and one `false`. + + + + 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. + +1. To change and display the value of `condition` in the browser, add markup that displays the status and a button. + + + +To verify that the directive works, click the button to change the value of `condition`. + +

    -{@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 shorthand} {@a asterisk} +## Structural directive shorthand +The asterisk, `*`, syntax on a structural directive, such as `*ngIf`, is shorthand that Angular interprets into a longer form. +Angular transforms the asterisk in front of a structural directive into an `` that surrounds the host element and its descendants. -## 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 following is an example of `*ngIf` that displays 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 moves to the `` where it becomes a property binding in square brackets, `[ngIf]`. +The rest of the `
    `, including its class attribute, moves inside the ``. +Angular does not create a real `` element, instead rendering only the `
    ` and a comment node placeholder to the DOM. +```html + +
    Mr. Nice
    -* 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: +``` +The following example compares the shorthand use of the asterisk in `*ngFor` with the longhand `` form: - - -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 ``. +Here, everything related to the `ngFor` structural directive applies to the ``. +All other bindings and attributes on the element apply to the `
    ` element within the ``. +Other modifiers on the host element, in addition to the `ngFor` string, remain in place as the element moves inside the ``. In this example, the `[class.odd]="odd"` stays on the `
    `. +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. -
    - - - -{@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. +The parser applies PascalCase to all directives and prefixes 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`. -* 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. +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 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. +For more information, see the [NgFor API](api/common/NgForOf "API: NgFor") and [NgForOf API](api/common/NgForOf) documentation. -* The [`NgFor` API guide](api/common/NgForOf "API: NgFor") -describes additional `NgFor` directive properties and context properties. +### Creating template fragments with `` -* The `NgForOf` directive implements `NgFor`. Read more about additional `NgForOf` directive properties and context properties in the [NgForOf API reference](api/common/NgForOf). +Angular's `` element defines a template that doesn't render anything by default. +With ``, you can render the content manually for full control over how the content displays. -### Writing your own structural directives +If there is no structural directive and you wrap some elements in an ``, those elements disappear. +In the following example, Angular does not render the middle "Hip!" in the phrase "Hip! Hip! Hooray!" because of the surrounding ``. -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: +## Structural directive syntax reference -- 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: +When you write your own structural directives, use the following syntax: ``` *:prefix="( :let | :expression ) (';' | ',')? ( :let | :as | :keyExp )*" ``` -The following tables describe each portion of the microsyntax grammar. - - +The following tables describe each portion of the structural directive grammar: - - - - + @@ -347,7 +188,6 @@ The following tables describe each portion of the microsyntax grammar.
    prefix HTML attribute key
    - @@ -363,15 +203,13 @@ The following tables describe each portion of the microsyntax grammar.
    +### How Angular translates shorthand -### Translation +Angular translates structural directive shorthand into the normal binding syntax as follows: -A microsyntax is translated to the normal binding syntax as follows: - - - + @@ -393,14 +231,14 @@ A microsyntax is translated to the normal binding syntax as follows:
    MicrosyntaxShorthand Translation
    -### Microsyntax examples +### Shorthand examples -The following table demonstrates how Angular desugars microsyntax. +The following table provides shorthand examples: - - + + @@ -421,445 +259,29 @@ The following table demonstrates how Angular desugars microsyntax.
    MicrosyntaxDesugaredShorthandHow Angular interprets the syntax
    *ngFor="let item of [1,2,3]"
    -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-reference-variables), -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 `