模板变量
Template variables
模板变量可以帮助你在模板的另一部分使用这个部分的数据。使用模板变量,你可以执行某些任务,比如响应用户输入或微调应用的表单。
Template variables help you use data from one part of a template in another part of the template. With template variables, you can perform tasks such as respond to user input or finely tune your application's forms.
模板变量可以引用这些东西:
A template variable can refer to the following:
模板中的 DOM 元素
a DOM element within a template
指令
a directive
元素
an element
语法
Syntax
在模板中,要使用井号 #
来声明一个模板变量。下列模板变量 #phone
语法在 <input>
元素上声明了一个名为 phone
的变量
In the template, you use the hash symbol, #
, to declare a template variable. The following template variable, #phone
, declares a phone
variable on an <input>
element.
<input #phone placeholder="phone number" />
你可以在组件模板中的任何地方引用某个模板变量。这里的 <button>
就引用了 phone
变量。
You can refer to a template variable anywhere in the component's template. Here, a <button>
further down the template refers to the phone
variable.
<input #phone placeholder="phone number" />
<!-- lots of other elements -->
<!-- phone refers to the input element; pass its `value` to an event handler -->
<button (click)="callPhone(phone.value)">Call</button>
Angular 是如何为模板变量赋值的
How Angular assigns values to template variables
Angular 根据你所声明的变量的位置给模板变量赋值:
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.
如果在标准的 HTML 标记上声明变量,该变量就会引用该元素。
If you declare the variable on a standard HTML tag, the variable refers to the element.
如果你在
<ng-template>
元素上声明变量,该变量就会引用一个TemplateRef
实例来代表此模板。关于<ng-template>
的更多信息,请参阅结构型指令 中的 Angular 如何使用*
语法部分。If you declare the variable on an
<ng-template>
element, the variable refers to aTemplateRef
instance, which represents the template. For more information on<ng-template>
, see How Angular uses the asterisk,*
, syntax in Structural directives.如果该变量在右侧指定了一个名字,比如
#var="ngModel"
,那么该变量就会引用所在元素上具有这个exportAs
名字的指令或组件。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 matchingexportAs
name.
将 NgForm
与模板变量一起使用
Using NgForm
with template variables
在大多数情况下,Angular 会把模板变量的值设置为它所在的元素。在前面的例子中, phone
引用的是电话号码 <input>
。该按钮的 click 处理程序会把这个 <input>
的值传给该组件的 callPhone()
方法。
In most cases, Angular sets the template variable's value to the element on which it occurs. 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.
这里的 NgForm
指令演示了如何通过引用指令的的 exportAs
名字来引用不同的值。在下面的例子中,模板变量 itemForm
在 HTML 中分别出现了三次。
The NgForm
directive demonstrates getting a reference to a different value by reference a directive's exportAs
name. In the following example, the template variable, itemForm
, appears three times separated by HTML.
<form #itemForm="ngForm" (ngSubmit)="onSubmit(itemForm)">
<label for="name">Name <input class="form-control" name="name" ngModel required />
</label>
<button type="submit">Submit</button>
</form>
<div [hidden]="!itemForm.form.valid">
<p>{{ submitMessage }}</p>
</div>
如果没有 ngForm
这个属性值,itemForm
引用的值将是 HTMLFormElement 也就是 <form>
元素。而 Component
和 Directive
之间的差异在于 Angular 在没有指定属性值的情况下,Angular 会引用 Component
,而 Directive
不会改变这种隐式引用(即它的宿主元素)。
Without the ngForm
attribute value, the reference value of itemForm
would be the HTMLFormElement, <form>
. There is, however, a difference between a Component
and a Directive
in that Angular references a Component
without specifying the attribute value, and a Directive
does not change the implicit reference, or the element.
而使用了 NgForm
之后,itemForm
就是对 NgForm 指令的引用,可以用它来跟踪表单中每一个控件的值和有效性。
With NgForm
, itemForm
is a reference to the NgForm directive with the ability to track the value and validity of every control in the form.
与原生的 <form>
元素不同, NgForm
指令有一个 form
属性。如果 itemForm.form.valid
无效,那么 NgForm
的 form
属性就会让你禁用提交按钮。
Unlike the native <form>
element, the NgForm
directive has a form
property. The NgForm
form
property allows you to disable the submit button if the itemForm.form.valid
is invalid.
模板变量的作用域
Template variable scope
你可以在包含此模板变量的模板中的任何地方引用它。而 结构型指令(如 *ngIf
和 *ngFor
或 <ng-template>
同样充当了模板的边界。你不能在这些边界之外访问其中的模板变量。
You can refer to a template variable anywhere within its surrounding template. Structural directives, such as *ngIf
and *ngFor
, or <ng-template>
act as a template boundary. You cannot access template variables outside of these boundaries.
同名变量在模板中只能定义一次,这样运行时它的值就是可预测的。
Define a variable only once in the template so the runtime value remains predictable.
在嵌套模板中访问
Accessing in a nested template
内部模板可以访问外模板定义的模板变量。
An inner template can access template variables that the outer template defines.
在下面的例子中,修改 <input>
中的文本值也会改变 <span>
中的值,因为 Angular 会立即通过模板变量 ref1
来更新这种变化。
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
.
<input #ref1 type="text" [(ngModel)]="firstExample" />
<span *ngIf="true">Value: {{ ref1.value }}</span>
在这种情况下,有一个包含这个 <span>
的隐式 <ng-template>
,而该变量的定义在该隐式模板之外。访问父模板中的模板变量是可行的,因为子模板会从父模板继承上下文。
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.
我们用更啰嗦的形式重写上述的代码,可以明确地显示出 <ng-template>
。
Rewriting the above code in a more verbose form explicitly shows the <ng-template>
.
<input #ref1 type="text" [(ngModel)]="firstExample" />
<!-- New template -->
<ng-template [ngIf]="true">
<!-- Since the context is inherited, the value is available to the new template -->
<span>Value: {{ ref1.value }}</span>
</ng-template>
但是,从外部的父模板访问本模板中的变量是行不通的。
However, accessing a template variable from outside the parent template doesn't work.
<input *ngIf="true" #ref2 type="text" [(ngModel)]="secondExample" />
<span>Value: {{ ref2?.value }}</span> <!-- doesn't work -->
这个更啰嗦的形式表明 ref2
位于外部的父模板中。
The verbose form shows that ref2
is outside the parent template.
<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>
考虑下面这个带 *ngFor
的使用范例。
Consider the following example that uses *ngFor
.
<ng-container *ngFor="let i of [1,2]">
<input #ref type="text" [value]="i" />
</ng-container>
{{ ref.value }}
这里,ref.value
不起作用。结构型指令 *ngFor
将模板实例化了两次,因为 *ngFor
在对数组中的两个条目进行迭代。因此不可能定义出 ref.value
指向的是谁。
Here, ref.value
doesn't work. The structural directive, *ngFor
instantiates the template twice because *ngFor
iterates over the two items in the array. It is impossible to define what the ref.value
reference signifies.
对于结构型指令,比如 *ngFor
或 *ngIf
,Angular 也无法知道模板是否曾被实例化过。
With structural directives, such as *ngFor
or *ngIf
, there is no way for Angular to know if a template is ever instantiated.
结果,Angular 无法访问该值并返回错误。
As a result, Angular isn't able to access the value and returns an error.
访问 <ng-template>
的模板变量
Accessing a template variable within <ng-template>
在 <ng-template>
上声明变量时,该变量会引用一个 TemplateRef
实例来表示该模板。
When you declare the variable on an <ng-template>
, the variable refers to a TemplateRef
instance, which represents the template.
<ng-template #ref3></ng-template>
<button (click)="log(ref3)">Log type of #ref</button>
在这个例子中,单击该按钮会调用 log()
函数,它把 #ref3
的值输出到控制台。因为 #ref
变量在 <ng-template>
上,所以它的值是一个 TemplateRef
。
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
.
下面是一个名为 TemplateRef
的 TemplateRef()
函数在浏览器控制台中展开时的输出。
The following is the expanded browser console output of the TemplateRef()
function with the name of TemplateRef
.
▼ ƒ TemplateRef()
name: "TemplateRef"
__proto__: Function
模板输入变量
Template input variable
模板输入变量是可以在模板的单个实例中引用的变量。你可以用 let
关键字声明模板输入变量,比如 let hero
。
A template input variable is a variable you can reference within a single instance of the template. You declare a template input variable using the let
keyword as in let hero
.
在这个例子中,有几个这样的变量:hero
、i
和 odd
。
There are several such variables in this example: hero
, i
, and odd
.
此变量的范围仅限于可复写模板中的单个实例。你可以在其他结构型指令的定义中再次使用相同的变量名。
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.
相反,你可以通过在变量名称前加上 #
来声明模板变量,如 #var
。模板变量引用其附加的元素、组件或指令。
In contrast, you declare a template variable by prefixing the variable name with #
, as in #var
. A template variable refers to its attached element, component, or directive.
模板输入变量和模板变量名称具有各自的名称空间。let hero
中的模板输入变量 hero
和 #hero
中的模板变量 hero
是不同的。
Template input variables and template variables names have their own namespaces. The template input variable hero
in let hero
is distinct from the template variable hero
in #hero
.