<button (click)="onSave()">Save</button>
The iconUrl
and onSave
are members of the AppComponent
class. They are not decorated with @Input()
or @Output
. Angular does not object.
iconUrl
和 onSave
是 AppComponent
类的成员。但它们并没有带 @Input()
或 @Output()
装饰器。 Angular 不在乎。
You can always bind to a public property of a component in its own template. It doesn't have to be an Input or Output property
你总是可以在组件自己的模板中绑定到组件的公共属性,而不用管它们是否输入(Input)属性或输出(Output)属性。
A component's class and template are closely coupled. They are both parts of the same thing. Together they are the component. Exchanges between a component class and its template are internal implementation details.
这是因为组件类和模板是紧耦合的,它们是同一个东西的两个部分,合起来构成组件。 组件类及其模板之间的交互属于实现细节。
You can also bind to a property of a different component. In such bindings, the other component's property is to the left of the (=
).
你也可以绑定到其它组件的属性。 这种绑定形式下,其它组件的属性位于等号(=
)的左侧。
In the following example, the AppComponent
template binds AppComponent
class members to properties of the HeroDetailComponent
whose selector is 'app-hero-detail'
.
下面的例子中,AppComponent
的模板把 AppComponent
类的成员绑定到了 HeroDetailComponent
(选择器为 'app-hero-detail'
) 的属性上。
The Angular compiler may reject these bindings with errors like this one:
Angular 的编译器可能会对这些绑定报错,就像这样:
You know that HeroDetailComponent
has hero
and deleteRequest
properties. But the Angular compiler refuses to recognize them.
你自己知道 HeroDetailComponent
有两个属性 hero
和 detectRequest
,但 Angular 编译器并不知道。
The Angular compiler won't bind to properties of a different component unless they are Input or Output properties.
Angular 编译器不会绑定到其它组件的属性上 —— 除非这些属性是输入或输出属性。
There's a good reason for this rule.
这条规则是有充分理由的。
It's OK for a component to bind to its own properties. The component author is in complete control of those bindings.
组件绑定到它自己的属性当然没问题。 该组件的作者对这些绑定有完全的控制权。
But other components shouldn't have that kind of unrestricted access. You'd have a hard time supporting your component if anyone could bind to any of its properties. Outside components should only be able to bind to the component's public binding API.
但是,其它组件不应该进行这种毫无限制的访问。 如果任何人都可以绑定到你的组件的任何属性上,那么这个组件就很难维护。 所以,外部组件应该只能绑定到组件的公共(允许绑定) API 上。
Angular asks you to be explicit about that API. It's up to you to decide which properties are available for binding by external components.
Angular 要求你显式声明那些 API。 它让你可以自己决定哪些属性是可以被外部组件绑定的。
public
是没用的linkYou can't use the TypeScript public and private access modifiers to shape the component's public binding API.
你不能用 TypeScript 的 public
和 private
访问控制符来标明组件的公共 API。
All data bound properties must be TypeScript public properties. Angular never binds to a TypeScript private property.
所有数据绑定属性必须是 TypeScript 的公共属性,Angular 永远不会绑定到 TypeScript 中的私有属性。
Angular requires some other way to identify properties that outside components are allowed to bind to. That other way is the @Input()
and @Output()
decorators.
因此,Angular 需要一些其它方式来标记出那些允许被外部组件绑定到的属性。 这种其它方式,就是 @Input()
和 @Output()
装饰器。
In the sample for this guide, the bindings to HeroDetailComponent
do not fail because the data bound properties are annotated with @Input()
and @Output()
decorators.
在本章的例子中,绑定到 HeroDetailComponent
不会失败,这是因为这些要进行数据绑定的属性都带有 @Input()
和 @Output()
装饰器。
Alternatively, you can identify members in the inputs
and outputs
arrays of the directive metadata, as in this example:
另外,还可以在指令元数据的 inputs
或 outputs
数组中标记出这些成员。比如这个例子:
Input properties usually receive data values. Output properties expose event producers, such as EventEmitter
objects.
输入属性通常接收数据值。 输出属性暴露事件生产者,如 EventEmitter
对象。
The terms input and output reflect the perspective of the target directive.
输入和输出这两个词是从目标指令的角度来说的。
HeroDetailComponent.hero
is an input property from the perspective of HeroDetailComponent
because data flows into that property from a template binding expression.
从 HeroDetailComponent
角度来看,HeroDetailComponent.hero
是个输入属性, 因为数据流从模板绑定表达式流入那个属性。
HeroDetailComponent.deleteRequest
is an output property from the perspective of HeroDetailComponent
because events stream out of that property and toward the handler in a template binding statement.
从 HeroDetailComponent
角度来看,HeroDetailComponent.deleteRequest
是个输出属性, 因为事件从那个属性流出,流向模板绑定语句中的处理器。
Sometimes the public name of an input/output property should be different from the internal name.
有时需要让输入/输出属性的公共名字不同于内部名字。
This is frequently the case with attribute directives. Directive consumers expect to bind to the name of the directive. For example, when you apply a directive with a myClick
selector to a <div>
tag, you expect to bind to an event property that is also called myClick
.
这是使用 attribute 指令时的常见情况。 指令的使用者期望绑定到指令名。例如,在 <div>
上用 myClick
选择器应用指令时, 希望绑定的事件属性也叫 myClick
。
However, the directive name is often a poor choice for the name of a property within the directive class. The directive name rarely describes what the property does. The myClick
directive name is not a good name for a property that emits click messages.
然而,在指令类中,直接用指令名作为自己的属性名通常都不是好的选择。 指令名很少能描述这个属性是干嘛的。 myClick
这个指令名对于用来发出 click 消息的属性就算不上一个好名字。
Fortunately, you can have a public name for the property that meets conventional expectations, while using a different name internally. In the example immediately above, you are actually binding through the myClick
alias to the directive's own clicks
property.
幸运的是,可以使用约定俗成的公共名字,同时在内部使用不同的名字。 在上面例子中,实际上是把 myClick
这个别名指向了指令自己的 clicks
属性。
You can specify the alias for the property name by passing it into the input/output decorator like this:
把别名传进@Input/@Output 装饰器,就可以为属性指定别名,就像这样:
You can also alias property names in the inputs
and outputs
arrays. You write a colon-delimited (:
) string with the directive property name on the left and the public alias on the right:
也可在 inputs
和 outputs
数组中为属性指定别名。 可以写一个冒号 (:
) 分隔的字符串,左侧是指令中的属性名,右侧则是公共别名。
The template expression language employs a subset of JavaScript syntax supplemented with a few special operators for specific scenarios. The next sections cover two of these operators: pipe and safe navigation operator.
模板表达式语言使用了 JavaScript 语法的子集,并补充了几个用于特定场景的特殊操作符。 下面介绍其中的两个:管道和安全导航操作符。
The result of an expression might require some transformation before you're ready to use it in a binding. For example, you might display a number as a currency, force text to uppercase, or filter a list and sort it.
在绑定之前,表达式的结果可能需要一些转换。例如,可能希望把数字显示成金额、强制文本变成大写,或者过滤列表以及进行排序。
Angular pipes are a good choice for small transformations such as these. Pipes are simple functions that accept an input value and return a transformed value. They're easy to apply within template expressions, using the pipe operator (|
):
Angular 管道对像这样的小型转换来说是个明智的选择。 管道是一个简单的函数,它接受一个输入值,并返回转换结果。 它们很容易用于模板表达式中,只要使用管道操作符 (|
) 就行了。
The pipe operator passes the result of an expression on the left to a pipe function on the right.
管道操作符会把它左侧的表达式结果传给它右侧的管道函数。
You can chain expressions through multiple pipes:
还可以通过多个管道串联表达式:
And you can also apply parameters to a pipe:
还能对它们使用参数:
The json
pipe is particularly helpful for debugging bindings:
json
管道对调试绑定特别有用:
The generated output would look something like this
它生成的输出是这样的:
The Angular safe navigation operator (?.
) is a fluent and convenient way to guard against null and undefined values in property paths. Here it is, protecting against a view render failure if the currentHero
is null.
Angular 的安全导航操作符 (?.
) 是一种流畅而便利的方式,用来保护出现在属性路径中 null 和 undefined 值。 下例中,当 currentHero
为空时,保护视图渲染器,让它免于失败。
What happens when the following data bound title
property is null?
如果下列数据绑定中 title
属性为空,会发生什么?
The view still renders but the displayed value is blank; you see only "The title is" with nothing after it. That is reasonable behavior. At least the app doesn't crash.
这个视图仍然被渲染出来,但是显示的值是空;只能看到 “The title is”,它后面却没有任何东西。 这是合理的行为。至少应用没有崩溃。
Suppose the template expression involves a property path, as in this next example that displays the name
of a null hero.
假设模板表达式涉及属性路径,在下例中,显示一个空 (null) 英雄的 firstName
。
JavaScript throws a null reference error, and so does Angular:
JavaScript 抛出了空引用错误,Angular 也是如此:
Worse, the entire view disappears.
晕,整个视图都不见了。
This would be reasonable behavior if the hero
property could never be null. If it must never be null and yet it is null, that's a programming error that should be caught and fixed. Throwing an exception is the right thing to do.
如果确信 hero
属性永远不可能为空,可以声称这是合理的行为。 如果它必须不能为空,但它仍然是空值,实际上是制造了一个编程错误,它应该被捕获和修复。 这种情况应该抛出异常。
On the other hand, null values in the property path may be OK from time to time, especially when the data are null now and will arrive eventually.
另一方面,属性路径中的空值可能会时常发生,特别是数据目前为空但最终会出现。
While waiting for data, the view should render without complaint, and the null property path should display as blank just as the title
property does.
当等待数据的时候,视图渲染器不应该抱怨,而应该把这个空属性路径显示为空白,就像上面 title
属性那样。
Unfortunately, the app crashes when the currentHero
is null.
不幸的是,当 currentHero
为空的时候,应用崩溃了。
You could code around that problem with *ngIf.
可以通过用NgIf代码环绕它来解决这个问题。
You could try to chain parts of the property path with &&
, knowing that the expression bails out when it encounters the first null.
或者可以尝试通过 &&
来把属性路径的各部分串起来,让它在遇到第一个空值的时候,就返回空。
These approaches have merit but can be cumbersome, especially if the property path is long. Imagine guarding against a null somewhere in a long property path such as a.b.c.d
.
这些方法都有价值,但是会显得笨重,特别是当这个属性路径非常长的时候。 想象一下在一个很长的属性路径(如 a.b.c.d
)中对空值提供保护。
The Angular safe navigation operator (?.
) is a more fluent and convenient way to guard against nulls in property paths. The expression bails out when it hits the first null value. The display is blank, but the app keeps rolling without errors.
Angular 安全导航操作符 (?.
) 是在属性路径中保护空值的更加流畅、便利的方式。 表达式会在它遇到第一个空值的时候跳出。 显示是空的,但应用正常工作,而没有发生错误。
It works perfectly with long property paths such as a?.b?.c?.d
.
在像 a?.b?.c?.d
这样的长属性路径中,它工作得很完美。back to top
As of Typescript 2.0, you can enforce strict null checking with the --strictNullChecks
flag. TypeScript then ensures that no variable is unintentionally null or undefined.
在 TypeScript 2.0 中,你可以使用 --strictNullChecks
标志强制开启严格空值检查。TypeScript 就会确保不存在意料之外的 null 或 undefined。
In this mode, typed variables disallow null and undefined by default. The type checker throws an error if you leave a variable unassigned or try to assign null or undefined to a variable whose type disallows null and undefined.
在这种模式下,有类型的变量默认是不允许 null 或 undefined 值的,如果有未赋值的变量,或者试图把 null 或 undefined 赋值给不允许为空的变量,类型检查器就会抛出一个错误。
The type checker also throws an error if it can't determine whether a variable will be null or undefined at runtime. You may know that can't happen but the type checker doesn't know. You tell the type checker that it can't happen by applying the post-fix non-null assertion operator (!).
如果类型检查器在运行期间无法确定一个变量是 null 或 undefined,那么它也会抛出一个错误。 你自己可能知道它不会为空,但类型检查器不知道。 所以你要告诉类型检查器,它不会为空,这时就要用到非空断言操作符。
The Angular non-null assertion operator (!
) serves the same purpose in an Angular template.
Angular 模板中的**非空断言操作符(!
)也是同样的用途。
For example, after you use *ngIf to check that hero
is defined, you can assert that hero
properties are also defined.
例如,在用*ngIf来检查过 hero
是已定义的之后,就可以断言 hero
属性一定是已定义的。
When the Angular compiler turns your template into TypeScript code, it prevents TypeScript from reporting that hero.name
might be null or undefined.
在 Angular 编译器把你的模板转换成 TypeScript 代码时,这个操作符会防止 TypeScript 报告 "hero.name
可能为 null 或 undefined"的错误。
Unlike the safe navigation operator, the non-null assertion operator does not guard against null or undefined. Rather it tells the TypeScript type checker to suspend strict null checks for a specific property expression.
与安全导航操作符不同的是,非空断言操作符不会防止出现 null 或 undefined。 它只是告诉 TypeScript 的类型检查器对特定的属性表达式,不做 "严格空值检测"。
You'll need this template operator when you turn on strict null checks. It's optional otherwise.
如果你打开了严格控制检测,那就要用到这个模板操作符,而其它情况下则是可选的。
$any
type cast function ($any( <expression> )
)link$any
($any( <表达式> ))linkSometimes a binding expression will be reported as a type error and it is not possible or difficult to fully specify the type. To silence the error, you can use the $any
cast function to cast the expression to the any
type.
有时候,绑定表达式可能会报类型错误,并且它不能或很难指定类型。要消除这种报错,你可以使用 $any
转换函数来把表达式转换成 any
类型。
In this example, when the Angular compiler turns your template into TypeScript code, it prevents TypeScript from reporting that marker
is not a member of the Hero
interface.
在这个例子中,当 Angular 编译器把模板转换成 TypeScript 代码时,$any
表达式可以防止 TypeScript 编译器报错说 marker
不是 Hero
接口的成员。
The $any
cast function can be used in conjunction with this
to allow access to undeclared members of the component.
$any
转换函数可以和 this
联合使用,以便访问组件中未声明过的成员。
The $any
cast function can be used anywhere in a binding expression where a method call is valid.
$any
转换函数可以在绑定表达式中任何可以进行方法调用的地方使用。
You've completed this survey of template syntax. Now it's time to put that knowledge to work on your own components and directives.
你完成了模板语法的概述。现在,该把如何写组件和指令的知识投入到实际工作当中了。