mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
docs: Understanding template variables updated (#45897)
This converts the "Template variables" doc to the new "Understanding" format and remove some irrelevant content. PR Close #45897
This commit is contained in:
committed by
Jessica Janiuk
parent
3c690bc1e9
commit
5879e4616f
@@ -1,15 +1,14 @@
|
||||
# Template variables
|
||||
# Understanding template variables
|
||||
|
||||
Template variables help you use data from one part of a template in another part of the template.
|
||||
Use template variables to perform tasks such as respond to user input or finely tune your application's forms.
|
||||
|
||||
A template variable can refer to the following:
|
||||
|
||||
* A DOM element within a template
|
||||
* A directive
|
||||
* An element
|
||||
* [TemplateRef](api/core/TemplateRef)
|
||||
* A [web component](https://developer.mozilla.org/docs/Web/Web_Components "MDN: Web Components")
|
||||
* a DOM element within a template
|
||||
* a directive or component
|
||||
* a [TemplateRef](api/core/TemplateRef) from an [ng-template](api/core/ng-template)
|
||||
* a <a href="https://developer.mozilla.org/en-US/docs/Web/Web_Components" title="MDN: Web Components">web component</a>
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -17,29 +16,35 @@ See the <live-example></live-example> for a working example containing the code
|
||||
|
||||
</div>
|
||||
|
||||
## Prerequisites
|
||||
|
||||
* [Understanding templates](guide/template-overview)
|
||||
|
||||
## Syntax
|
||||
|
||||
In the template, you use the hash \(`#`\) character to declare a template variable.
|
||||
The following template variable, `#phone`, declares a `phone` variable on an `<input>` element.
|
||||
In the template, you use the hash symbol, `#`, to declare a template variable.
|
||||
The following template variable, `#phone`, declares a `phone` variable with the `<input>` element as its value.
|
||||
|
||||
<code-example header="src/app/app.component.html" path="template-reference-variables/src/app/app.component.html" region="ref-var"></code-example>
|
||||
<code-example path="template-reference-variables/src/app/app.component.html" region="ref-var" header="src/app/app.component.html"></code-example>
|
||||
|
||||
Refer to a template variable anywhere in the component's template.
|
||||
Here, a `<button>` further down the template refers to the `phone` variable.
|
||||
|
||||
<code-example header="src/app/app.component.html" path="template-reference-variables/src/app/app.component.html" region="ref-phone"></code-example>
|
||||
<code-example path="template-reference-variables/src/app/app.component.html" region="ref-phone" header="src/app/app.component.html"></code-example>
|
||||
|
||||
## How Angular assigns values to template variables
|
||||
|
||||
Angular assigns a template variable a value based on where you declare the variable:
|
||||
|
||||
* If you declare the variable on a component, the variable refers to the component instance
|
||||
* If you declare the variable on a standard HTML tag, the variable refers to the element
|
||||
* If you declare the variable on an `<ng-template>` element, the variable refers to a `TemplateRef` instance, which represents the template.
|
||||
For more information on `<ng-template>`, see [How Angular uses the asterisk, `*`, syntax](guide/structural-directives#asterisk) in [Structural directives](guide/structural-directives).
|
||||
* If you declare the variable on a component, the variable refers to the component instance.
|
||||
* If you declare the variable on a standard HTML tag, the variable refers to the element.
|
||||
* If you declare the variable on an `<ng-template>` element, the variable refers to a `TemplateRef` instance which represents the template.
|
||||
For more information on `<ng-template>`, see [How Angular uses the asterisk, `*`, syntax](guide/structural-directives#asterisk) in [Structural directives](guide/structural-directives).
|
||||
|
||||
* If the variable specifies a name on the right-hand side, such as `#var="ngModel"`, the variable refers to the directive or component on the element with a matching `exportAs` name.
|
||||
<!--todo: What does the second half of this mean?^^ Can we explain this more fully? Could I see a working example? -kw -->
|
||||
## Variable specifying a name
|
||||
|
||||
* If the variable specifies a name on the right-hand side, such as `#var="ngModel"`, the variable refers to the directive or component on the element with a matching `exportAs` name.
|
||||
<!-- What does the second half of this mean?^^ Can we explain this more fully? Could I see a working example? -kw -->
|
||||
|
||||
### Using `NgForm` with template variables
|
||||
|
||||
@@ -47,34 +52,21 @@ In most cases, Angular sets the template variable's value to the element on whic
|
||||
In the previous example, `phone` refers to the phone number `<input>`.
|
||||
The button's click handler passes the `<input>` value to the component's `callPhone()` method.
|
||||
|
||||
The `NgForm` directive is applied by Angular on `<form>` elements. This example demonstrates getting a reference to a different value by referencing a directive's `exportAs` name.
|
||||
The `NgForm` directive demonstrates getting a reference to a different value by referencing a directive's `exportAs` name.
|
||||
In the following example, the template variable, `itemForm`, appears three times separated by HTML.
|
||||
|
||||
<code-example header="src/app/hero-form.component.html" path="template-reference-variables/src/app/app.component.html" region="ngForm"></code-example>
|
||||
<code-example path="template-reference-variables/src/app/app.component.html" region="ngForm" header="src/app/hero-form.component.html"></code-example>
|
||||
|
||||
Without the `ngForm` attribute value, the reference value of `itemForm` would be
|
||||
the [HTMLFormElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLFormElement), `<form>`.
|
||||
|
||||
With `NgForm`, `itemForm` is a reference to the [NgForm](api/forms/NgForm "API: NgForm") directive with the ability to track the value and validity of every control in the form.
|
||||
|
||||
Unlike the native `<form>` element, the `NgForm` directive has a `form` property.
|
||||
The `NgForm` `form` property lets you disable the submit button if the `itemForm.form.valid` is invalid.
|
||||
|
||||
## Default reference type without assigned value
|
||||
|
||||
When declaring a template reference variable on an element without defining a value for it, its returned type will reflect the type of element it's applied to:
|
||||
|
||||
- **Native element**: specific subclass of [HTMLElement](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement)
|
||||
- **Component**: instance of the specific Component class
|
||||
- **NgTemplate**: TemplateRef
|
||||
|
||||
Referencing an element by its directive needs the directive `exportAs` property set as reference value.
|
||||
In case of an unspecified variable value, the reference will return an `HTMLElement`, even if the element has one or more directive applied to itself.
|
||||
If an element is an Angular Component, a reference with no attribute value will automatically reference the component instance. Otherwise, a reference with no value will reference the DOM element, even if the element has one or more directives applied to it.
|
||||
<!-- What is the train of thought from talking about a form element to the difference between a component and a directive? Why is the component directive conversation relevant here? -kw I agree -alex -->
|
||||
|
||||
## Template variable scope
|
||||
|
||||
Refer to a template variable anywhere within its surrounding template.
|
||||
[Structural directives](guide/built-in-directives), such as `*ngIf` and `*ngFor`, or `<ng-template>` act as a template boundary.
|
||||
You cannot access template variables outside of these boundaries.
|
||||
Just like variables in JavaScript or TypeScript code, template variables are scoped to the template that declares them.
|
||||
|
||||
Similarly, [Structural directives](guide/built-in-directives) such as `*ngIf` and `*ngFor`, or `<ng-template>` declarations create a new nested template scope, much like JavaScript's control flow statements like `if` and `for` create new lexical scopes. You cannot access template variables within one of these structural directives from outside of its boundaries.
|
||||
|
||||
<div class="alert is-helpful">
|
||||
|
||||
@@ -88,126 +80,51 @@ An inner template can access template variables that the outer template defines.
|
||||
|
||||
In the following example, changing the text in the `<input>` changes the value in the `<span>` because Angular immediately updates changes through the template variable, `ref1`.
|
||||
|
||||
<code-example header="src/app/app.component.html" path="template-reference-variables/src/app/app.component.html" region="template-ref-vars-scope1"></code-example>
|
||||
<code-example path="template-reference-variables/src/app/app.component.html" region="template-ref-vars-scope1" header="src/app/app.component.html"></code-example>
|
||||
|
||||
In this case, there is an implied `<ng-template>` around the `<span>` and the definition of the variable is outside of it.
|
||||
Accessing a template variable from the parent template works because the child template inherits the context from the parent template.
|
||||
In this case, the `*ngIf` on `<span>` creates a new template scope, which includes the `ref1` variable from its parent scope.
|
||||
|
||||
Rewriting the preceding code in a more verbose form explicitly shows the `<ng-template>`.
|
||||
However, accessing a template variable from a child scope in the parent template doesn't work:
|
||||
|
||||
<code-example format="html" language="html">
|
||||
```html
|
||||
<input *ngIf="true" #ref2 type="text" [(ngModel)]="secondExample" />
|
||||
<span>Value: {{ ref2?.value }}</span> <!-- doesn't work -->
|
||||
```
|
||||
|
||||
<input #ref1 type="text" [(ngModel)]="firstExample" />
|
||||
|
||||
<!-- New template -->
|
||||
<ng-template [ngIf]="true">
|
||||
<!-- Because the context is inherited, the value is available to the new template -->
|
||||
<span>Value: {{ ref1.value }}</span>
|
||||
</ng-template>
|
||||
|
||||
</code-example>
|
||||
|
||||
However, accessing a template variable from outside the parent template doesn't work.
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<input *ngIf="true" #ref2 type="text" [(ngModel)]="secondExample" />
|
||||
<span>Value: {{ ref2?.value }}</span> <!-- doesn't work -->
|
||||
|
||||
</code-example>
|
||||
|
||||
The verbose form shows that `ref2` is outside the parent template.
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ng-template [ngIf]="true">
|
||||
<!-- The reference is defined within a template -->
|
||||
<input #ref2 type="text" [(ngModel)]="secondExample" />
|
||||
</ng-template>
|
||||
<!-- ref2 accessed from outside that template doesn't work -->
|
||||
<span>Value: {{ ref2?.value }}</span>
|
||||
|
||||
</code-example>
|
||||
|
||||
Consider the following example that uses `*ngFor`.
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ng-container *ngFor="let i of [1,2]">
|
||||
<input #ref type="text" [value]="i" />
|
||||
</ng-container>
|
||||
{{ ref.value }}
|
||||
|
||||
</code-example>
|
||||
|
||||
Here, `ref.value` doesn't work.
|
||||
Verbose syntax of the same loop shows why:
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ng-template ngFor let-i [ngForOf]="[1,2]">
|
||||
<input #ref type="text" [value]="i" />
|
||||
</ng-template>
|
||||
{{ ref.value }}
|
||||
|
||||
</code-example>
|
||||
|
||||
The interpolation trying to access property `ref.value` occurs outside of the referenced element's parent template, making it unreachable.
|
||||
|
||||
Moving the interpolation inside the template makes the variable available. Now it references the correct distinct value for each element the loop renders.
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ng-template ngFor let-i [ngForOf]="[1,2]">
|
||||
<input #ref type="text" [value]="i" />
|
||||
{{ ref.value }}
|
||||
</ng-template>
|
||||
|
||||
</code-example>
|
||||
|
||||
This snippet shows 2 `<input>` elements, with their respective value printed.
|
||||
|
||||
### Accessing a template variable within `<ng-template>`
|
||||
|
||||
When you declare the variable on an `<ng-template>`, the variable refers to a `TemplateRef` instance, which represents the template.
|
||||
|
||||
<code-example header="src/app/app.component.html" path="template-reference-variables/src/app/app.component.html" region="template-ref"></code-example>
|
||||
|
||||
In this example, clicking the button calls the `log()` function, which outputs the value of `#ref3` to the console.
|
||||
Because the `#ref` variable is on an `<ng-template>`, the value is `TemplateRef`.
|
||||
|
||||
The following is the expanded browser console output of the `TemplateRef()` function with the name of `TemplateRef`.
|
||||
|
||||
<code-example format="shell" language="shell">
|
||||
|
||||
▾ ƒ TemplateRef()
|
||||
name: "TemplateRef"
|
||||
__proto__: Function
|
||||
|
||||
</code-example>
|
||||
|
||||
<a id="template-input-variable"></a>
|
||||
<a id="template-input-variables"></a>
|
||||
Here, `ref2` is declared in the child scope created by `*ngIf`, and is not accessible from the parent template.
|
||||
|
||||
{@a template-input-variable}
|
||||
{@a template-input-variables}
|
||||
## Template input variable
|
||||
|
||||
A *template input variable* is a variable to reference within a single instance of the template.
|
||||
You declare a template input variable using the `let` keyword as in `let hero`.
|
||||
A _template input variable_ is a variable with a value that is set when an instance of that template is created. See: [Writing structural directives](https://angular.io/guide/structural-directives)
|
||||
|
||||
If its value is omitted, it gets the `$implicit` template context's property value.
|
||||
Template input variables can be seen in action in the long-form usage of `NgFor`:
|
||||
|
||||
There are several such variables in this example: `hero`, `i`, and `odd`.
|
||||
The first one takes the value of the iterated item, because `NgForOf` assigns that to `$implicit`
|
||||
```html
|
||||
<ul>
|
||||
<ng-template ngFor let-hero [ngForOf]="heroes">
|
||||
<li>{{hero.name}}
|
||||
</ng-template>
|
||||
</ul>
|
||||
```
|
||||
|
||||
<code-example format="html" language="html">
|
||||
|
||||
<ng-template ngFor #hero let-hero [ngForOf]="heroes" let-i="index" let-odd="odd">
|
||||
<div [class]="{'odd-row': odd}">{{i}}:{{hero.name}}</div>
|
||||
</ng-template>
|
||||
The `NgFor` directive will instantiate this <ng-template> once for each hero in the `heroes` array, and will set the `hero` variable for each instance accordingly.
|
||||
|
||||
</code-example>
|
||||
When an `<ng-template>` is instantiated, multiple named values can be passed which can be bound to different template input variables. The right-hand side of the `let-` declaration of an input variable can specify which value should be used for that variable.
|
||||
|
||||
The variable's scope is limited to a single instance of the repeated template.
|
||||
Use the same variable name again in the definition of other structural directives.
|
||||
`NgFor` for example also provides access to the `index` of each hero in the array:
|
||||
|
||||
When in the same template a _template reference variable_ and a _template input variable_ with the same name get declared, the latter takes precedence.
|
||||
```html
|
||||
<ul>
|
||||
<ng-template ngFor let-hero let-i="index" [ngForOf]="heroes">
|
||||
<li>Hero number {{i}}: {{hero.name}}
|
||||
</ng-template>
|
||||
</ul>
|
||||
```
|
||||
|
||||
## What’s next
|
||||
|
||||
[Writing structural directives](https://angular.io/guide/structural-directives)
|
||||
|
||||
@reviewed 2022-05-12
|
||||
|
||||
Reference in New Issue
Block a user