# Template syntax # 模板语法 The Angular application manages what the user sees and can do, achieving this through the interaction of a component class instance (the *component*) and its user-facing template. Angular 应用管理着用户之所见和所为,并通过 Component 类的实例(*组件*)和面向用户的模板交互来实现这一点。 You may be familiar with the component/template duality from your experience with model-view-controller (MVC) or model-view-viewmodel (MVVM). In Angular, the component plays the part of the controller/viewmodel, and the template represents the view. 从使用模型-视图-控制器 (MVC) 或模型-视图-视图模型 (MVVM) 的经验中,很多开发人员都熟悉了组件和模板这两个概念。 在 Angular 中,组件扮演着控制器或视图模型的角色,模板则扮演视图的角色。 This page is a comprehensive technical reference to the Angular template language. It explains basic principles of the template language and describes most of the syntax that you'll encounter elsewhere in the documentation. 这是一篇关于 Angular 模板语言的技术大全。 它解释了模板语言的基本原理,并描述了你将在文档中其它地方遇到的大部分语法。 Many code snippets illustrate the points and concepts, all of them available in the . 这里还有很多代码片段用来解释技术点和概念,它们全都在中。 {@a html} ## HTML in templates ## 模板中的 HTML HTML is the language of the Angular template. Almost all HTML syntax is valid template syntax. The ` Syntax" is the interpolated evil title. "Template alert("evil never sleeps")Syntax" is the property bound evil title.
{@a other-bindings} ## Attribute, class, and style bindings ## attribute、class 和 style 绑定 The template syntax provides specialized one-way bindings for scenarios less well-suited to property binding. 模板语法为那些不太适合使用属性绑定的场景提供了专门的单向数据绑定形式。 To see attribute, class, and style bindings in a functioning app, see the especially for this section. 要在运行中的应用查看 Attribute 绑定、类绑定和样式绑定,请参见 特别是对于本节。 ### Attribute binding ### attribute 绑定 Set the value of an attribute directly with an **attribute binding**. This is the only exception to the rule that a binding sets a target property and the only binding that creates and sets an attribute. 可以直接使用 **Attribute 绑定**设置 Attribute 的值。一般来说,绑定时设置的是目标的 Property,而 Attribute 绑定是唯一的例外,它创建和设置的是 Attribute。 Usually, setting an element property with a [property binding](guide/template-syntax#property-binding) is preferable to setting the attribute with a string. However, sometimes there is no element property to bind, so attribute binding is the solution. 通常,使用 [Property 绑定](guide/template-syntax#property-binding)设置元素的 Property 优于使用字符串设置 Attribute。但是,有时没有要绑定的元素的 Property,所以其解决方案就是 Attribute 绑定。 Consider the [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) and [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG). They are purely attributes, don't correspond to element properties, and don't set element properties. In these cases, there are no property targets to bind to. 考虑 [ARIA](https://developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA) 和 [SVG](https://developer.mozilla.org/en-US/docs/Web/SVG)。它们都纯粹是 Attribute,不对应于元素的 Property,也不能设置元素的 Property。 在这些情况下,就没有要绑定到的目标 Property。 Attribute binding syntax resembles property binding, but instead of an element property between brackets, start with the prefix `attr`, followed by a dot (`.`), and the name of the attribute. You then set the attribute value, using an expression that resolves to a string, or remove the attribute when the expression resolves to `null`. Attribute 绑定的语法类似于 Property 绑定,但其括号之间不是元素的 Property,而是由前缀 `attr`、点( `.` )和 Attribute 名称组成。然后,你就可以使用能解析为字符串的表达式来设置该 Attribute 的值,或者当表达式解析为 `null` 时删除该 Attribute。 One of the primary use cases for attribute binding is to set ARIA attributes, as in this example: attribute 绑定的主要用例之一是设置 ARIA attribute(译注:ARIA 指无障碍功能,用于给残障人士访问互联网提供便利), 就像这个例子中一样:
#### `colspan` and `colSpan` #### `colspan` 和 `colSpan` Notice the difference between the `colspan` attribute and the `colSpan` property. 注意 `colspan` Attribute 和 `colSpan` Property 之间的区别。 If you wrote something like this: 如果你这样写: <tr><td colspan="{{1 + 1}}">Three-Four</td></tr> You'd get this error: 你会收到如下错误: Template parse errors: Can't bind to 'colspan' since it isn't a known native property As the message says, the `` element does not have a `colspan` property. This is true because `colspan` is an attribute—`colSpan`, with a capital `S`, is the corresponding property. Interpolation and property binding can set only *properties*, not attributes. 如错误消息所示,`` 元素没有 `colspan` 这个 Property。这是正确的,因为 `colspan` 是一个 Attribute,而 `colSpan` (`colSpan` 中的 `S` 是大写)则是相应的 Property。插值和 Property 绑定只能设置 *Property*,不能设置 Attribute。 Instead, you'd use property binding and write it like this: 相反,你可以使用 Property 绑定并将其改写为:

### Class binding ### 类绑定 Here's how to set the `class` attribute without a binding in plain HTML: 下面是在普通 HTML 中不用绑定来设置 `class` Attribute 的方法: ```html
Some text
``` You can also add and remove CSS class names from an element's `class` attribute with a **class binding**. 你还可以使用**类绑定**来为一个元素添加和移除 CSS 类。 To create a single class binding, start with the prefix `class` followed by a dot (`.`) and the name of the CSS class (for example, `[class.foo]="hasFoo"`). Angular adds the class when the bound expression is truthy, and it removes the class when the expression is falsy (with the exception of `undefined`, see [styling delegation](#styling-delegation)). 要创建单个类的绑定,请使用 `class` 前缀,紧跟一个点(`.`),再跟上 CSS 类名,比如 `[class.foo]="hasFoo"`。 当绑定表达式为真值的时候,Angular 就会加上这个类,为假值则会移除,但 `undefined` 是假值中的例外,参见[样式委派](#styling-delegation) 部分。 To create a binding to multiple classes, use a generic `[class]` binding without the dot (for example, `[class]="classExpr"`). The expression can be a space-delimited string of class names, or you can format it as an object with class names as the keys and truthy/falsy expressions as the values. With object format, Angular will add a class only if its associated value is truthy. 要想创建多个类的绑定,请使用通用的 `[class]` 形式来绑定类,而不要带点,比如 `[class]="classExpr"`。 该表达式可以是空格分隔的类名字符串,或者用一个以类名为键、真假值表达式为值的对象。 当使用对象格式时,Angular 只会加上那些相关的值为真的类名。 It's important to note that with any object-like expression (`object`, `Array`, `Map`, `Set`, etc), the identity of the object must change for the class list to be updated. Updating the property without changing object identity will have no effect. 一定要注意,在对象型表达式中(如 `object`、`Array`、`Map`、`Set` 等),当这个类列表改变时,对象的引用也必须修改。仅仅修改其属性而不修改对象引用是无法生效的。 If there are multiple bindings to the same class name, conflicts are resolved using [styling precedence](#styling-precedence). 如果有多处绑定到了同一个类名,出现的冲突将根据[样式的优先级规则](#styling-precedence)进行解决。
Binding Type Syntax Input Type Example Input Values
绑定类型 语法 输入类型 输入值范例
Single class binding [class.foo]="hasFoo" boolean | undefined | null true, false
单个类绑定 [class.foo]="hasFoo" boolean | undefined | null true, false
Multi-class binding [class]="classExpr" string "my-class-1 my-class-2 my-class-3"
多个类绑定 [class]="classExpr" string "my-class-1 my-class-2 my-class-3"
{[key: string]: boolean | undefined | null} {foo: true, bar: false}
Array<string> ['foo', 'bar']
The [NgClass](#ngclass) directive can be used as an alternative to direct `[class]` bindings. However, using the above class binding syntax without `NgClass` is preferred because due to improvements in class binding in Angular, `NgClass` no longer provides significant value, and might eventually be removed in the future. 尽管此技术适用于切换单个类名,但在需要同时管理多个类名时请考虑使用 [`NgClass`](guide/template-syntax#ngClass) 指令。
### Style binding ### 样式绑定 Here's how to set the `style` attribute without a binding in plain HTML: 下面演示了如何不通过绑定在普通 HTML 中设置 `style` 属性: ```html
Some text
``` You can also set styles dynamically with a **style binding**. 你还可以通过**样式绑定**来动态设置样式。 To create a single style binding, start with the prefix `style` followed by a dot (`.`) and the name of the CSS style property (for example, `[style.width]="width"`). The property will be set to the value of the bound expression, which is normally a string. Optionally, you can add a unit extension like `em` or `%`, which requires a number type. 要想创建单个样式的绑定,请以 `style` 前缀开头,紧跟一个点(`.`),再跟着 CSS 样式的属性名,比如 `[style.width]="width"`。 该属性将会被设置为绑定表达式的值,该值通常为字符串。 不过你还可以添加一个单位表达式,比如 `em` 或 `%`,这时候该值就要是一个 `number` 类型。
Note that a _style property_ name can be written in either [dash-case](guide/glossary#dash-case), as shown above, or [camelCase](guide/glossary#camelcase), such as `fontSize`. 注意,*样式属性*命名方法可以用[中线命名法](guide/glossary#dash-case),像上面的一样 也可以用[驼峰式命名法](guide/glossary#camelcase),如 `fontSize`。
If there are multiple styles you'd like to toggle, you can bind to the `[style]` property directly without the dot (for example, `[style]="styleExpr"`). The expression attached to the `[style]` binding is most often a string list of styles like `"width: 100px; height: 100px;"`. 如果要切换多个样式,你可以直接绑定到 `[style]` 属性而不用点(比如,`[style]="styleExpr"`)。赋给 `[style]` 的绑定表达式通常是一系列样式组成的字符串,比如 `"width: 100px; height: 100px;"`。 You can also format the expression as an object with style names as the keys and style values as the values, like `{width: '100px', height: '100px'}`. It's important to note that with any object-like expression (`object`, `Array`, `Map`, `Set`, etc), the identity of the object must change for the class list to be updated. Updating the property without changing object identity will have no effect. 你也可以把该表达式格式化成一个以样式名为键、以样式值为值的对象,比如 `{width: '100px', height: '100px'}`。一定要注意,对于任何对象型的表达式( 如 `object`,`Array`,`Map`,`Set` 等),当这个样式列表改变时,对象的引用也必须修改。仅仅修改其属性而不修改对象引用是无法生效的。。 If there are multiple bindings to the same style property, conflicts are resolved using [styling precedence rules](#styling-precedence). 如果有多处绑定了同一个样式属性,则会使用[样式的优先级规则](#styling-precedence)来解决冲突。
Binding Type Syntax Input Type Example Input Values
绑定类型 语法 输入类型 输入值范例
Single style binding [style.width]="width" string | undefined | null "100px"
单一样式绑定 [style.width]="width" string | undefined | null "100px"
Single style binding with units [style.width.px]="width" number | undefined | null 100
带单位的单一样式绑定 [style.width.px]="width" number | undefined | null 100
Multi-style binding [style]="styleExpr" string "width: 100px; height: 100px"
多个样式绑定 [style]="styleExpr" string "width: 100px; height: 100px"
{[key: string]: string | undefined | null} {width: '100px', height: '100px'}
Array<string> ['width', '100px']
The [NgStyle](#ngstyle) directive can be used as an alternative to direct `[style]` bindings. However, using the above style binding syntax without `NgStyle` is preferred because due to improvements in style binding in Angular, `NgStyle` no longer provides significant value, and might eventually be removed in the future. [NgStyle](#ngstyle) 指令可以作为 `[style]` 绑定的替代指令。但是,应该把上面这种 `[style]` 样式绑定语法作为首选,因为随着 Angular 中样式绑定的改进,`NgStyle` 将不再提供重要的价值,并最终在未来的某个版本中删除。
{@a styling-precedence} ### Styling Precedence ### 样式的优先级规则 A single HTML element can have its CSS class list and style values bound to multiple sources (for example, host bindings from multiple directives). 一个 HTML 元素可以把它的 CSS 类列表和样式值绑定到多个来源(例如,来自多个指令的宿主 `host` 绑定)。 When there are multiple bindings to the same class name or style property, Angular uses a set of precedence rules to resolve conflicts and determine which classes or styles are ultimately applied to the element. 当对同一个类名或样式属性存在多个绑定时,Angular 会使用一组优先级规则来解决冲突,并确定最终哪些类或样式会应用到该元素中。

Styling precedence (highest to lowest)

样式的优先级规则(从高到低)

1. Template bindings 模板绑定 1. Property binding (for example, `
` or `
`) 属性绑定(例如 `
` 或 `
`) 1. Map binding (for example, `
` or `
`) Map 绑定(例如,`
` 或 `
` ) 1. Static value (for example, `
` or `
`) 静态值(例如 `
` 或 `
` ) 1. Directive host bindings 指令宿主绑定 1. Property binding (for example, `host: {'[class.foo]': 'hasFoo'}` or `host: {'[style.color]': 'color'}`) 属性绑定(例如,`host: {'[class.foo]': 'hasFoo'}` 或 `host: {'[style.color]': 'color'}` ) 1. Map binding (for example, `host: {'[class]': 'classExpr'}` or `host: {'[style]': 'styleExpr'}`) Map 绑定(例如,`host: {'[class]': 'classExpr'}` 或者 `host: {'[style]': 'styleExpr'}` ) 1. Static value (for example, `host: {'class': 'foo'}` or `host: {'style': 'color: blue'}`) 静态值(例如,`host: {'class': 'foo'}` 或 `host: {'style': 'color: blue'}` ) 1. Component host bindings 组件宿主绑定 1. Property binding (for example, `host: {'[class.foo]': 'hasFoo'}` or `host: {'[style.color]': 'color'}`) 属性绑定(例如,`host: {'[class.foo]': 'hasFoo'}` 或 `host: {'[style.color]': 'color'}` ) 1. Map binding (for example, `host: {'[class]': 'classExpr'}` or `host: {'[style]': 'styleExpr'}`) Map 绑定(例如,`host: {'[class]': 'classExpr'}` 或者 `host: {'[style]': 'styleExpr'}` ) 1. Static value (for example, `host: {'class': 'foo'}` or `host: {'style': 'color: blue'}`) 静态值(例如,`host: {'class': 'foo'}` 或 `host: {'style': 'color: blue'}` )
The more specific a class or style binding is, the higher its precedence. 某个类或样式绑定越具体,它的优先级就越高。 A binding to a specific class (for example, `[class.foo]`) will take precedence over a generic `[class]` binding, and a binding to a specific style (for example, `[style.bar]`) will take precedence over a generic `[style]` binding. 对具体类(例如 `[class.foo]` )的绑定优先于一般化的 `[class]` 绑定,对具体样式(例如 `[style.bar]` )的绑定优先于一般化的 `[style]` 绑定。 Specificity rules also apply when it comes to bindings that originate from different sources. It's possible for an element to have bindings in the template where it's declared, from host bindings on matched directives, and from host bindings on matched components. 当处理不同来源的绑定时,也适用这种基于具体度的规则。 某个元素可能在声明它的模板中有一些绑定、在所匹配的指令中有一些宿主绑定、在所匹配的组件中有一些宿主绑定。 Template bindings are the most specific because they apply to the element directly and exclusively, so they have the highest precedence. 模板中的绑定是最具体的,因为它们直接并且唯一地应用于该元素,所以它们具有最高的优先级。 Directive host bindings are considered less specific because directives can be used in multiple locations, so they have a lower precedence than template bindings. 指令的宿主绑定被认为不太具体,因为指令可以在多个位置使用,所以它们的优先级低于模板绑定。 Directives often augment component behavior, so host bindings from components have the lowest precedence. 指令经常会增强组件的行为,所以组件的宿主绑定优先级最低。 In addition, bindings take precedence over static attributes. 另外,绑定总是优先于静态属性。 In the following case, `class` and `[class]` have similar specificity, but the `[class]` binding will take precedence because it is dynamic. 在下面的例子中,`class` 和 `[class]` 具有相似的具体度,但 `[class]` 绑定优先,因为它是动态的。 {@a styling-delegation} ### Delegating to styles with lower precedence ### 委托优先级较低的样式 It is possible for higher precedence styles to "delegate" to lower precedence styles using `undefined` values. Whereas setting a style property to `null` ensures the style is removed, setting it to `undefined` will cause Angular to fall back to the next-highest precedence binding to that style. 更高优先级的样式可以使用 `undefined` 值“委托”给低级的优先级样式。虽然把 style 属性设置为 `null` 可以确保该样式被移除,但把它设置为 `undefined` 会导致 Angular 回退到该样式的次高优先级。 For example, consider the following template: 例如,考虑以下模板: Imagine that the `dirWithHostBinding` directive and the `comp-with-host-binding` component both have a `[style.width]` host binding. In that case, if `dirWithHostBinding` sets its binding to `undefined`, the `width` property will fall back to the value of the `comp-with-host-binding` host binding. However, if `dirWithHostBinding` sets its binding to `null`, the `width` property will be removed entirely. 想象一下,`dirWithHostBinding` 指令和 `comp-with-host-binding` 组件都有 `[style.width]` 宿主绑定。在这种情况下,如果 `dirWithHostBinding` 把它的绑定设置为 `undefined`,则 `width` 属性将回退到 `comp-with-host-binding` 主机绑定的值。但是,如果 `dirWithHostBinding` 把它的绑定设置为 `null`,那么 `width` 属性就会被完全删除。 {@a event-binding} ## Event binding `(event)` ## 事件绑定 `(event)` Event binding allows you to listen for certain events such as keystrokes, mouse movements, clicks, and touches. For an example demonstrating all of the points in this section, see the event binding example. 事件绑定允许你监听某些事件,比如按键、鼠标移动、点击和触屏。要查看本节中所有要点的演示,请参见事件绑定范例。 Angular event binding syntax consists of a **target event** name within parentheses on the left of an equal sign, and a quoted template statement on the right. The following event binding listens for the button's click events, calling the component's `onSave()` method whenever a click occurs: Angular 的事件绑定语法由等号左侧带圆括号的**目标事件**和右侧引号中的[模板语句](guide/template-syntax#template-statements)组成。 下面事件绑定监听按钮的点击事件。每当点击发生时,都会调用组件的 `onSave()` 方法。 ### Target event ### 目标事件 As above, the target is the button's click event. 如前所述,其目标就是此按钮的单击事件。 Alternatively, use the `on-` prefix, known as the canonical form: 有些人更喜欢带 `on-` 前缀的备选形式,称之为**规范形式**: Element events may be the more common targets, but Angular looks first to see if the name matches an event property of a known directive, as it does in the following example: 元素事件可能是更常见的目标,但 Angular 会先看这个名字是否能匹配上已知指令的事件属性,就像下面这个例子: If the name fails to match an element event or an output property of a known directive, Angular reports an “unknown directive” error. 如果这个名字没能匹配到元素事件或已知指令的输出属性,Angular 就会报“未知指令”错误。 ### *$event* and event handling statements ### *$event* 和事件处理语句 In an event binding, Angular sets up an event handler for the target event. 在事件绑定中,Angular 会为目标事件设置事件处理器。 When the event is raised, the handler executes the template statement. The template statement typically involves a receiver, which performs an action in response to the event, such as storing a value from the HTML control into a model. 当事件发生时,这个处理器会执行模板语句。 典型的模板语句通常涉及到响应事件执行动作的接收器,例如从 HTML 控件中取得值,并存入模型。 The binding conveys information about the event. This information can include data values such as an event object, string, or number named `$event`. 绑定会通过**名叫 `$event` 的事件对象**传递关于此事件的信息(包括数据值)。 The target event determines the shape of the `$event` object. If the target event is a native DOM element event, then `$event` is a [DOM event object](https://developer.mozilla.org/en-US/docs/Web/Events), with properties such as `target` and `target.value`. 事件对象的形态取决于目标事件。如果目标事件是原生 DOM 元素事件, `$event` 就是 [DOM 事件对象](https://developer.mozilla.org/en-US/docs/Web/Events),它有像 `target` 和 `target.value` 这样的属性。 Consider this example: 考虑这个范例: This code sets the `` `value` property by binding to the `name` property. To listen for changes to the value, the code binds to the `input` event of the `` element. When the user makes changes, the `input` event is raised, and the binding executes the statement within a context that includes the DOM event object, `$event`. 上面的代码在把输入框的 `value` 属性绑定到 `name` 属性。 要监听对值的修改,代码绑定到输入框的 `input` 事件。 当用户造成更改时,`input` 事件被触发,并在包含了 DOM 事件对象 (`$event`) 的上下文中执行这条语句。 To update the `name` property, the changed text is retrieved by following the path `$event.target.value`. 要更新 `name` 属性,就要通过路径 `$event.target.value` 来获取更改后的值。 If the event belongs to a directive—recall that components are directives—`$event` has whatever shape the directive produces. 如果事件属于指令(回想一下,组件是指令的一种),那么 `$event` 具体是什么由指令决定。 ### Custom events with `EventEmitter` ### 使用 `EventEmitter` 实现自定义事件 Directives typically raise custom events with an Angular [EventEmitter](api/core/EventEmitter). The directive creates an `EventEmitter` and exposes it as a property. The directive calls `EventEmitter.emit(payload)` to fire an event, passing in a message payload, which can be anything. Parent directives listen for the event by binding to this property and accessing the payload through the `$event` object. 通常,指令使用 Angular [EventEmitter](api/core/EventEmitter) 来触发自定义事件。 指令创建一个 `EventEmitter` 实例,并且把它作为属性暴露出来。 指令调用 `EventEmitter.emit(payload)` 来触发事件,可以传入任何东西作为消息载荷。 父指令通过绑定到这个属性来监听事件,并通过 `$event` 对象来访问载荷。 Consider an `ItemDetailComponent` that presents item information and responds to user actions. Although the `ItemDetailComponent` has a delete button, it doesn't know how to delete the hero. It can only raise an event reporting the user's delete request. 假设 `ItemDetailComponent` 用于显示英雄的信息,并响应用户的动作。 虽然 `ItemDetailComponent` 包含删除按钮,但它自己并不知道该如何删除这个英雄。 最好的做法是触发事件来报告“删除用户”的请求。 Here are the pertinent excerpts from that `ItemDetailComponent`: 下面的代码节选自 `ItemDetailComponent`: The component defines a `deleteRequest` property that returns an `EventEmitter`. When the user clicks *delete*, the component invokes the `delete()` method, telling the `EventEmitter` to emit an `Item` object. 组件定义了 `deleteRequest` 属性,它是 `EventEmitter` 实例。 当用户点击*删除*时,组件会调用 `delete()` 方法,让 `EventEmitter` 发出一个 `Item` 对象。 Now imagine a hosting parent component that binds to the `deleteRequest` event of the `ItemDetailComponent`. 现在,假设有个宿主的父组件,它绑定了 `ItemDetailComponent` 的 `deleteRequest` 事件。 When the `deleteRequest` event fires, Angular calls the parent component's `deleteItem()` method, passing the *item-to-delete* (emitted by `ItemDetail`) in the `$event` variable. 当 `deleteRequest` 事件触发时,Angular 调用父组件的 `deleteItem` 方法, 在 `$event` 变量中传入*要删除的英雄*(来自 `ItemDetail`)。 ### Template statements have side effects ### 模板语句有副作用 Though [template expressions](guide/template-syntax#template-expressions) shouldn't have [side effects](guide/template-syntax#avoid-side-effects), template statements usually do. The `deleteItem()` method does have a side effect: it deletes an item. 虽然[模板表达式](guide/template-syntax#template-expressions)不应该有[副作用](guide/template-syntax#avoid-side-effects),但是模板语句通常会有。这里的 `deleteItem()` 方法就有一个副作用:它删除了一个条目。 Deleting an item updates the model, and depending on your code, triggers other changes including queries and saving to a remote server. These changes propagate through the system and ultimately display in this and other views. 删除这个英雄会更新模型,还可能触发其它修改,包括向远端服务器的查询和保存。 这些变更通过系统进行扩散,并最终显示到当前以及其它视图中。
{@a two-way} ## Two-way binding `[(...)]` ## 双向绑定 `[(...)]` Two-way binding gives your app a way to share data between a component class and its template. 双向绑定为你的应用程序提供了一种在组件类及其模板之间共享数据的方式。 For a demonstration of the syntax and code snippets in this section, see the two-way binding example. 有关本节中语法和代码段的演示,请参见 双向绑定范例。 ### Basics of two-way binding ### 双向绑定的基础知识 Two-way binding does two things: 双向绑定会做两件事: 1. Sets a specific element property. 设置特定的元素属性。 1. Listens for an element change event. 监听元素的变更事件。 Angular offers a special _two-way data binding_ syntax for this purpose, `[()]`. The `[()]` syntax combines the brackets of property binding, `[]`, with the parentheses of event binding, `()`. Angular 为此提供了一种特殊*的双向数据绑定*语法 `[()]`。`[()]` 语法将属性绑定的括号 `[]` 与事件绑定的括号 `()` 组合在一起。
[( )] = banana in a box
[( )] = 盒子里的香蕉
Visualize a *banana in a box* to remember that the parentheses go _inside_ the brackets. 想象*盒子里的香蕉*来记住方括号套圆括号。
The `[()]` syntax is easy to demonstrate when the element has a settable property called `x` and a corresponding event named `xChange`. Here's a `SizerComponent` that fits this pattern. It has a `size` value property and a companion `sizeChange` event: `[()]` 语法很容易想明白:该元素具有名为 `x` 的可设置属性和名为 `xChange` 的相应事件。 `SizerComponent` 就是用的这种模式。它具有一个名为 `size` 的值属性和一个与之相伴的 `sizeChange` 事件: The initial `size` is an input value from a property binding. Clicking the buttons increases or decreases the `size`, within min/max value constraints, and then raises, or emits, the `sizeChange` event with the adjusted size. `size` 的初始值来自属性绑定的输入值。单击按钮可在最小值/最大值范围内增大或减小 `size`,然后带上调整后的大小发出 `sizeChange` 事件。 Here's an example in which the `AppComponent.fontSizePx` is two-way bound to the `SizerComponent`: 下面的例子中,`AppComponent.fontSize` 被双向绑定到 `SizerComponent`: The `AppComponent.fontSizePx` establishes the initial `SizerComponent.size` value. `AppComponent.fontSizePx` 建立初始 `SizerComponent.size` 值。 Clicking the buttons updates the `AppComponent.fontSizePx` via the two-way binding. The revised `AppComponent.fontSizePx` value flows through to the _style_ binding, making the displayed text bigger or smaller. 单击按钮就会通过双向绑定更新 `AppComponent.fontSizePx`。修改后的 `AppComponent.fontSizePx` 值将传递到*样式*绑定,从而使显示的文本更大或更小。 The two-way binding syntax is really just syntactic sugar for a _property_ binding and an _event_ binding. Angular desugars the `SizerComponent` binding into this: 双向绑定语法实际上是*属性*绑定和*事件绑定*的语法糖。 Angular 将 `SizerComponent` 的绑定分解成这样: The `$event` variable contains the payload of the `SizerComponent.sizeChange` event. Angular assigns the `$event` value to the `AppComponent.fontSizePx` when the user clicks the buttons. `$event` 变量包含了 `SizerComponent.sizeChange` 事件的荷载。 当用户点击按钮时,Angular 将 `$event` 赋值给 `AppComponent.fontSizePx`。 ### Two-way binding in forms ### 表单中的双向绑定 The two-way binding syntax is a great convenience compared to separate property and event bindings. It would be convenient to use two-way binding with HTML form elements like `` and `` 和 `` element's `value` property and `input` event: 通过分别绑定到 `` 元素的 `value` 属性和 `input` 事件,可以达到同样的效果: To streamline the syntax, the `ngModel` directive hides the details behind its own `ngModel` input and `ngModelChange` output properties: 为了简化语法,`ngModel` 指令把技术细节隐藏在其输入属性 `ngModel` 和输出属性 `ngModelChange` 的后面: The `ngModel` data property sets the element's value property and the `ngModelChange` event property listens for changes to the element's value. `ngModel` 输入属性会设置该元素的值,并通过 `ngModelChange` 的输出属性来监听元素值的变化。 #### `NgModel` and value accessors #### `NgModel` 和值访问器 The details are specific to each kind of element and therefore the `NgModel` directive only works for an element supported by a [ControlValueAccessor](api/forms/ControlValueAccessor) that adapts an element to this protocol. Angular provides *value accessors* for all of the basic HTML form elements and the [Forms](guide/forms) guide shows how to bind to them. 这些技术细节是针对每种具体元素的,因此 `NgModel` 指令仅适用于通过 [ControlValueAccessor](api/forms/ControlValueAccessor) 适配过这种协议的元素。Angular 已经为所有基本的 HTML 表单元素提供了*值访问器*,[表单](guide/forms)一章示范了如何绑定到它们。 You can't apply `[(ngModel)]` to a non-form native element or a third-party custom component until you write a suitable value accessor. For more information, see the API documentation on [DefaultValueAccessor](https://angular.io/api/forms/DefaultValueAccessor). 在编写适当的值访问器之前,不能将 `[(ngModel)]` 应用于非表单的原生元素或第三方自定义组件。欲知详情,参见[DefaultValueAccessor](https://angular.cn/api/forms/DefaultValueAccessor)上的 API 文档。 You don't need a value accessor for an Angular component that you write because you can name the value and event properties to suit Angular's basic [two-way binding syntax](guide/template-syntax#two-way) and skip `NgModel` altogether. The `sizer` in the [Two-way Binding](guide/template-syntax#two-way) section is an example of this technique. 你不一定非用为所编写的 Angular 组件提供值访问器,因为你还可以把值属性和事件属性命名为符合 Angular 的基本[双向绑定语法](guide/template-syntax#two-way)的形式,并完全跳过 `NgModel`。[双向绑定](guide/template-syntax#two-way)部分的 `sizer` 是此技术的一个示例。 Separate `ngModel` bindings are an improvement over binding to the element's native properties, but you can streamline the binding with a single declaration using the `[(ngModel)]` syntax: 单独的 `ngModel` 绑定是对绑定到元素的原生属性方式的一种改进,但你可以使用 `[(ngModel)]` 语法来通过单个声明简化绑定: This `[(ngModel)]` syntax can only _set_ a data-bound property. If you need to do something more, you can write the expanded form; for example, the following changes the `` value to uppercase: 此 `[(ngModel)]` 语法只能*设置*数据绑定属性。如果你要做得更多,可以编写扩展表单。例如,下面的代码将 `` 值更改为大写: Here are all variations in action, including the uppercase version: 这里是所有这些变体的动画,包括这个大写转换的版本:
{@a structural-directives} ## Built-in _structural_ directives ## 内置*结构型*指令 Structural directives are responsible for HTML layout. They shape or reshape the DOM's structure, typically by adding, removing, and manipulating the host elements to which they are attached. 结构型指令的职责是 HTML 布局。 它们塑造或重塑 DOM 的*结构*,这通常是通过添加、移除和操纵它们所附加到的宿主元素来实现的。 This section is an introduction to the common built-in structural directives: 本节会介绍常见的内置结构型指令: * [`NgIf`](guide/template-syntax#ngIf)—conditionally creates or destroys subviews from the template. [`NgIf`](guide/template-syntax#ngIf) —— 从模板中创建或销毁子视图。 * [`NgFor`](guide/template-syntax#ngFor)—repeat a node for each item in a list. [`NgFor`](guide/template-syntax#ngFor) —— 为列表中的每个条目重复渲染一个节点。 * [`NgSwitch`](guide/template-syntax#ngSwitch)—a set of directives that switch among alternative views. [`NgSwitch`](guide/template-syntax#ngSwitch) —— 一组在备用视图之间切换的指令。
The deep details of structural directives are covered in the [Structural Directives](guide/structural-directives) guide, which explains the following: [结构型指令](guide/structural-directives)一章涵盖了结构型指令的详细内容,它解释了以下内容: * Why you [prefix the directive name with an asterisk (\*)](guide/structural-directives#the-asterisk--prefix). 为什么[在要指令名称前加上星号(\*)](guide/structural-directives#the-asterisk--prefix)。 * Using [``](guide/structural-directives#ngcontainer "") to group elements when there is no suitable host element for the directive. 当指令没有合适的宿主元素时,使用 [``](guide/structural-directives#ngcontainer "<ng-container>") 对元素进行分组。 * How to write your own structural directive. 如何写自己的结构型指令。 * That you can only apply [one structural directive](guide/structural-directives#one-per-element "one per host element") to an element. 你只能往一个元素上应用[一个结构型指令](guide/structural-directives#one-per-element "one per host element")。

{@a ngIf} ### NgIf You can add or remove an element from the DOM by applying an `NgIf` directive to a host element. Bind the directive to a condition expression like `isActive` in this example. 你可以通过将 `NgIf` 指令应用在宿主元素上来从 DOM 中添加或删除元素。在此示例中,将指令绑定到了条件表达式,例如 `isActive`。
Don't forget the asterisk (`*`) in front of `ngIf`. For more information on the asterisk, see the [asterisk (*) prefix](guide/structural-directives#the-asterisk--prefix) section of [Structural Directives](guide/structural-directives). 不要忘了 `ngIf` 前面的星号(`*`)。有关星号的更多信息,请参见 [结构型指令](guide/structural-directives)中的[星号(\*)前缀](guide/structural-directives#the-asterisk--prefix)部分。
When the `isActive` expression returns a truthy value, `NgIf` adds the `ItemDetailComponent` to the DOM. When the expression is falsy, `NgIf` removes the `ItemDetailComponent` from the DOM, destroying that component and all of its sub-components. 当 `isActive` 表达式返回真值时,`NgIf` 会把 `ItemDetailComponent` 添加到 DOM 中。当表达式为假值时,`NgIf` 将从 DOM 中删除 `ItemDetailComponent`,从而销毁该组件及其所有子组件。 #### Show/hide vs. `NgIf` #### 显示/隐藏与 `NgIf` Hiding an element is different from removing it with `NgIf`. For comparison, the following example shows how to control the visibility of an element with a [class](guide/template-syntax#class-binding) or [style](guide/template-syntax#style-binding) binding. 隐藏元素与使用 `NgIf` 删除元素不同。为了进行比较,下面的示例演示如何使用[类](guide/template-syntax#class-binding)或[样式](guide/template-syntax#style-binding)绑定来控制元素的可见性。 When you hide an element, that element and all of its descendants remain in the DOM. All components for those elements stay in memory and Angular may continue to check for changes. You could be holding onto considerable computing resources and degrading performance unnecessarily. 隐藏元素时,该元素及其所有后代仍保留在 DOM 中。这些元素的所有组件都保留在内存中,Angular 会继续做变更检查。它可能会占用大量计算资源,并且会不必要地降低性能。 `NgIf` works differently. When `NgIf` is `false`, Angular removes the element and its descendants from the DOM. It destroys their components, freeing up resources, which results in a better user experience. `NgIf` 工作方式有所不同。如果 `NgIf` 为 `false`,则 Angular 将从 DOM 中删除该元素及其后代。这销毁了它们的组件,释放了资源,从而带来更好的用户体验。 If you are hiding large component trees, consider `NgIf` as a more efficient alternative to showing/hiding. 如果要隐藏大型组件树,请考虑使用 `NgIf` 作为显示/隐藏的更有效替代方法。
For more information on `NgIf` and `ngIfElse`, see the [API documentation about NgIf](api/common/NgIf). 有关 `NgIf` 和 `ngIfElse` 的更多信息,请参阅 [关于 NgIf 的 API 文档](api/common/NgIf)。
#### Guard against null #### 防范空指针错误 Another advantage of `ngIf` is that you can use it to guard against null. Show/hide is best suited for very simple use cases, so when you need a guard, opt instead for `ngIf`. Angular will throw an error if a nested expression tries to access a property of `null`. `ngIf` 另一个优点是你可以使用它来防范空指针错误。显示/隐藏就是最合适的极简用例,当你需要防范时,请改用 `ngIf` 代替。如果其中嵌套的表达式尝试访问 `null` 的属性,Angular 将引发错误。 The following shows `NgIf` guarding two `
`s. The `currentCustomer` name appears only when there is a `currentCustomer`. The `nullCustomer` will not be displayed as long as it is `null`. 下面的例子中 `NgIf` 保护着两个 `
`。仅当存在 `currentCustomer` 时,才会显示 `currentCustomer` 名称。除非它为 `null` 否则不会显示 `nullCustomer`。
See also the [safe navigation operator](guide/template-syntax#safe-navigation-operator "Safe navigation operator (?.)") below. 另请参见下面的[安全导航运算符](guide/template-syntax#safe-navigation-operator "安全导航运算符(?.)")。

{@a ngFor} ### `NgFor` `NgFor` is a repeater directive—a way to present a list of items. You define a block of HTML that defines how a single item should be displayed and then you tell Angular to use that block as a template for rendering each item in the list. The text assigned to `*ngFor` is the instruction that guides the repeater process. `NgFor` 是一个重复器指令 —— 一种用来显示条目列表的方法。你定义了一个 HTML 块,该 HTML 块定义了应如何显示单个条目,然后告诉 Angular 以该块为模板来渲染列表中的每个条目。赋值给 `*ngFor` 的文本是用来指导重复器工作过程的指令。 The following example shows `NgFor` applied to a simple `
`. (Don't forget the asterisk (`*`) in front of `ngFor`.) 以下示例显示了如何将 `NgFor` 应用于简单的 `
`。(不要忘了 `ngFor` 前面的星号(`*`)。)
Don't forget the asterisk (`*`) in front of `ngFor`. For more information on the asterisk, see the [asterisk (*) prefix](guide/structural-directives#the-asterisk--prefix) section of [Structural Directives](guide/structural-directives). 不要忘了 `ngFor` 前面的星号(`*`)。有关星号的更多信息,请参见[结构型指令](guide/structural-directives)中的[星号(\*)前缀](guide/structural-directives#the-asterisk--prefix)部分。
You can also apply an `NgFor` to a component element, as in the following example. 你还可以将 `NgFor` 应用于组件元素,如以下示例所示。 {@a microsyntax}
*ngFor microsyntax
`*ngFor` 微语法
The string assigned to `*ngFor` is not a [template expression](guide/template-syntax#template-expressions). Rather, it's a *microsyntax*—a little language of its own that Angular interprets. The string `"let item of items"` means: 赋值给 `*ngFor` 的字符串不是[模板表达式](guide/template-syntax#template-expressions)。而是一个*微语法* —— 由 Angular 解释的一种小型语言。字符串 `"let item of items"` 的意思是: > *Take each item in the `items` array, store it in the local `item` looping variable, and make it available to the templated HTML for each iteration.* > *将 `items` 数组中的每个条目存储在局部循环变量 `item` 中,并使其可用于每次迭代的模板 HTML 中。* 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 microsyntax, see the [Structural Directives](guide/structural-directives#microsyntax) guide. Angular 将该指令转换为包裹着宿主元素的 ``,然后反复使用此模板为列表中的每个 `item` 创建一组新的元素和绑定。有关微语法的更多信息,请参见[结构型指令](guide/structural-directives#microsyntax)一章。
{@a template-input-variable} {@a template-input-variables} #### Template input variables #### 模板输入变量 The `let` keyword before `item` creates a template input variable called `item`. The `ngFor` directive iterates over the `items` array returned by the parent component's `items` property and sets `item` to the current item from the array during each iteration. `item` 前面的 `let` 关键字创建了一个名为 `item` 的模板输入变量。`ngFor` 指令迭代父组件的 `items` 属性所返回的 `items` 数组,并在每次迭代期间将 `item` 设置为该数组中的当前条目。 Reference `item` within the `ngFor` host element as well as within its descendants to access the item's properties. The following example references `item` first in an interpolation and then passes in a binding to the `item` property of the `` component. `ngFor` 的宿主元素及其后代中可引用 `item`,来访问该条目的属性。以下示例首先在插值中引用 `item`,然后把一个绑定表达式传入 `` 组件的 `item` 属性。 For more information about template input variables, see [Structural Directives](guide/structural-directives#template-input-variable). 有关模板输入变量的更多信息,请参见[结构型指令](guide/structural-directives#template-input-variable)。 #### `*ngFor` with `index` #### `*ngFor` 与 `index` The `index` property of the `NgFor` directive context returns the zero-based index of the item in each iteration. You can capture the `index` in a template input variable and use it in the template. `NgFor` 指令上下文中的 `index` 属性在每次迭代中返回该条目的从零开始的索引。 你可以在模板输入变量中捕获 `index`,并在模板中使用它。 The next example captures the `index` in a variable named `i` and displays it with the item name. 下面的例子在名为 `i` 的变量中捕获 `index`,并将其与条目名称一起显示。
`NgFor` is implemented by the `NgForOf` directive. Read more about the other `NgForOf` context values such as `last`, `even`, and `odd` in the [NgForOf API reference](api/common/NgForOf). 要学习更多的*类似 index* 的值,例如 `last`、`even` 和 `odd`,请参阅 [NgFor API 参考](api/common/NgForOf)。
{@a trackBy} #### *ngFor with `trackBy` #### 带 `trackBy` 的 `*ngFor` If you use `NgFor` with large lists, a small change to one item, such as removing or adding an item, can trigger a cascade of DOM manipulations. For example, re-querying the server could reset a list with all new item objects, even when those items were previously displayed. In this case, Angular sees only a fresh list of new object references and has no choice but to replace the old DOM elements with all new DOM elements. 如果将 `NgFor` 与大型列表一起使用,则对某个条目的较小更改(例如删除或添加一项)就会触发一系列 DOM 操作。 例如,重新查询服务器可能会重置包含所有新条目对象的列表,即使先前已显示这些条目也是如此。在这种情况下,Angular 只能看到由新的对象引用组成的新列表,它别无选择,只能用所有新的 DOM 元素替换旧的 DOM 元素。 You can make this more efficient with `trackBy`. Add a method to the component that returns the value `NgFor` should track. In this case, that value is the hero's `id`. If the `id` has already been rendered, Angular keeps track of it and doesn't re-query the server for the same `id`. 你可以使用 `trackBy` 来让它更加高效。向该组件添加一个方法,该方法返回 `NgFor` 应该跟踪的值。这个例子中,该值是英雄的 `id`。如果 `id` 已经被渲染,Angular 就会跟踪它,而不会重新向服务器查询相同的 `id`。 In the microsyntax expression, set `trackBy` to the `trackByItems()` method. 在微语法表达式中,将 `trackBy` 设置为 `trackByItems()` 方法。 Here is an illustration of the `trackBy` effect. "Reset items" creates new items with the same `item.id`s. "Change ids" creates new items with new `item.id`s. 这就是 `trackBy` 效果的说明。“Reset items” 将创建具有相同 `item.id` 的新条目。“Change ids” 将使用新的 `item.id` 创建新条目。 * With no `trackBy`, both buttons trigger complete DOM element replacement. 如果没有 `trackBy`,这些按钮都会触发完全的 DOM 元素替换。 * With `trackBy`, only changing the `id` triggers element replacement. 有了 `trackBy`,则只有修改了 `id` 的按钮才会触发元素替换。
Built-in directives use only public APIs; that is, they do not have special access to any private APIs that other directives can't access. 内置指令仅仅使用了公共 API。也就是说,它们没有用到任何其它指令无权访问的私有 API。

{@a ngSwitch} ## The `NgSwitch` directives ## `NgSwitch` 指令 NgSwitch is like the JavaScript `switch` statement. It displays one element from among several possible elements, based on a switch condition. Angular puts only the selected element into the DOM. NgSwitch 类似于 JavaScript `switch` 语句。它根据切换条件显示几个可能的元素中的一个。Angular 只会将选定的元素放入 DOM。 `NgSwitch` is actually a set of three, cooperating directives: `NgSwitch`, `NgSwitchCase`, and `NgSwitchDefault` as in the following example. `NgSwitch` 实际上是三个协作指令的集合: `NgSwitch`,`NgSwitchCase` 和 `NgSwitchDefault`,如以下示例所示。 `NgSwitch` is the controller directive. Bind it to an expression that returns the *switch value*, such as `feature`. Though the `feature` value in this example is a string, the switch value can be of any type. `NgSwitch` 是控制器指令。把它绑定到一个返回*开关值*的表达式,例如 `feature`。尽管此示例中的 `feature` 值是字符串,但开关值可以是任何类型。 **Bind to `[ngSwitch]`**. You'll get an error if you try to set `*ngSwitch` because `NgSwitch` is an *attribute* directive, not a *structural* directive. Rather than touching the DOM directly, it changes the behavior of its companion directives. **绑定到 `[ngSwitch]`**。如果试图写成 `*ngSwitch`,就会出现错误,因为 `NgSwitch` 是*属性型*指令,而不是*结构型*指令。它不会直接接触 DOM,而是会更改与之相伴的指令的行为。 **Bind to `*ngSwitchCase` and `*ngSwitchDefault`**. The `NgSwitchCase` and `NgSwitchDefault` directives are _structural_ directives because they add or remove elements from the DOM. **绑定到 `*ngSwitchCase` 和 `*ngSwitchDefault`** `NgSwitchCase` 和 `NgSwitchDefault` 指令都是*结构型指令*,因为它们会从 DOM 中添加或移除元素。 * `NgSwitchCase` adds its element to the DOM when its bound value equals the switch value and removes its bound value when it doesn't equal the switch value. 当 `NgSwitchCase` 的绑定值等于开关值时,就将其元素添加到 DOM 中;否则从 DOM 中删除。 * `NgSwitchDefault` adds its element to the DOM when there is no selected `NgSwitchCase`. `NgSwitchDefault` 会在没有任何一个 `NgSwitchCase` 被选中时把它所在的元素加入 DOM 中。 The switch directives are particularly useful for adding and removing *component elements*. This example switches among four `item` components defined in the `item-switch.components.ts` file. Each component has an `item` [input property](guide/template-syntax#inputs-outputs "Input property") which is bound to the `currentItem` of the parent component. 开关指令对于添加和删除*组件元素*特别有用。本示例在 `item-switch.components.ts` 文件中定义的四个 `item` 组件之间切换。每个组件都有一个名叫 `item` 的[输入属性](guide/template-syntax#inputs-outputs "输入属性"),它会绑定到父组件的 `currentItem`。 Switch directives work as well with native elements and web components too. For example, you could replace the `` switch case with the following. 开关指令也同样适用于原生元素和 Web Component。 比如,你可以把 `` 分支替换为如下代码。
{@a template-reference-variable} {@a template-reference-variables--var-} {@a ref-vars} {@a ref-var} ## Template reference variables (`#var`) ## 模板引用变量( `#var` ) A **template reference variable** is often a reference to a DOM element within a template. It can also refer to a directive (which contains a component), an element, [TemplateRef](api/core/TemplateRef), or a web component. **模板引用变量**通常是对模板中 DOM 元素的引用。它还可以引用指令(包含组件)、元素、[TemplateRef](api/core/TemplateRef) 或 [Web Component](https://developer.mozilla.org/en-US/docs/Web/Web_Components "MDN:Web Component")。 For a demonstration of the syntax and code snippets in this section, see the template reference variables example. 有关本节中语法和代码段的演示,请参见模板参考变量示例。 Use the hash symbol (#) to declare a reference variable. The following reference variable, `#phone`, declares a `phone` variable on an `` element. 使用井号(#)声明模板引用变量。以下模板引用变量 `#phone` 会在 `` 元素上声明了一个 `phone` 变量。 You can refer to a template reference variable anywhere in the component's template. Here, a `