删除不必要的“我们”和“一个”

This commit is contained in:
Yang Lin 2016-11-26 14:29:09 +08:00
parent 2b3c8e5a64
commit 121e760fc5
1 changed files with 93 additions and 93 deletions

View File

@ -11,48 +11,48 @@ include ../_util-fns
It's more challenging to create a cohesive data entry experience that guides the
user efficiently and effectively through the workflow behind the form.
任何经验丰富的Web开发人员都能使用适当的标签拼凑出一个HTML表单。
但是,要想做出一个具有贴心的数据输入体验的表单,
引导用户明晰、高效地完成表单背后的工作流程,这个挑战就大多了。
任何经验丰富的Web开发人员都能使用适当的标签拼凑出HTML表单。
但是,要想做出具有贴心的数据输入体验的表单,
引导用户明晰、高效地完成表单背后的工作流程,挑战就大多了。
*That* takes design skills that are, to be frank, well out of scope for this chapter.
*这当中*所需要的设计技能,坦白讲,确实超出了本章的范围。
坦白地讲,*这当中*所需要的设计技能超出了本章的范围。
It also takes framework support for
**two-way data binding, change tracking, validation, and error handling**
... which we shall cover in this chapter on Angular forms.
但是,它也需要框架支持,来实现**双向数据绑定、变更跟踪、有效性验证和错误处理**……
这些Angular表单相关的内容属于本章的范围
**双向数据绑定、变更跟踪、有效性验证和错误处理**等功能离不开框架的支持。
本章将介绍Angular表单相关的内容
We will build a simple form from scratch, one step at a time. Along the way we'll learn how to
我们将从零构建一个简单的表单,把它简化到一次一步。通过这种方式,我们将学到如何:
下面,从零开始,一步一步构建出一个简单的表单。在这个过程中,我们将学会如何:
- build an Angular form with a component and template
- 使用组件和模板构建一个Angular表单
使用组件和模板构建Angular表单
- two-way data bind with `[(ngModel)]` syntax for reading and writing values to input controls
- 使用`[(ngModel)]`语法实现双向数据绑定,以便于读取和写入输入控件的值
`[(ngModel)]`语法实现双向数据绑定,用于读取和写入输入控件的值
- track the change state and validity of form controls using `ngModel` in combination with a form
- 结合表单来使用`ngModel`,我们可以跟踪表单控件的状态变化和有效性
结合表单来使用`ngModel`可以跟踪表单控件的状态变化和有效性
- provide strong visual feedback using special CSS classes that track the state of the controls
- 使用特殊的CSS类来跟踪控件状态,并提供强烈的视觉反馈
使用特殊的 CSS 类来跟踪控件状态,并提供强烈的视觉反馈
- display validation errors to users and enable/disable form controls
- 向用户显示有效性验证的错误提示,以及启用/禁用表单控件
向用户显示验证错误提示,以及启用/禁用表单控件
- use [template reference variables](./template-syntax.html#ref-vars) for sharing information among HTML elements
- 使用[模板引用变量](./template-syntax.html#ref-vars)在HTML元素之间共享信息
用[模板引用变量](./template-syntax.html#ref-vars)在 HTML 元素之间共享信息
Run the <live-example></live-example>.
@ -67,27 +67,27 @@ include ../_util-fns
Many of us will build forms by writing templates in the Angular [template syntax](./template-syntax.html) with
the form-specific directives and techniques described in this chapter.
通常,我们用Angular[模板语法](./template-syntax.html)编写模板,结合本章所描述的表单专用指令和技术来构建表单。
通常,使用Angular[模板语法](./template-syntax.html)编写模板,结合本章所描述的表单专用指令和技术来构建表单。
.l-sub-section
:marked
That's not the only way to create a form but it's the way we'll cover in this chapter.
这不是创建表单的唯一方式,但它是我们将在本章中使用的方式。(译注Angular支持的另一种方式叫做模型驱动表单Model-Driven Forms)
这不是创建表单的唯一方式,本章中只介绍模板驱动的表单。(译注Angular支持的另一种方式叫做模型驱动表单Model-Driven Forms)
:marked
We can build almost any form we need with an Angular template &mdash; login forms, contact forms ... pretty much any business forms.
We can lay out the controls creatively, bind them to data, specify validation rules and display validation errors,
conditionally enable or disable specific controls, trigger built-in visual feedback, and much more.
利用Angular模板我们可以构建几乎所有表单 —— 登录表单、联系人表单…… 以及任何的商务表单。
我们可以创造性的摆放各种控件、把它们绑定到数据、指定校验规则、显示校验错误、有条件的禁用或
利用Angular模板可以构建几乎所有表单 —— 登录表单、联系人表单…… 以及任何的商务表单。
可以创造性的摆放各种控件、把它们绑定到数据、指定校验规则、显示校验错误、有条件的禁用或
启用特定的控件、触发内置的视觉反馈等等,不胜枚举。
It will be pretty easy because Angular handles many of the repetitive, boiler plate tasks we'd
otherwise wrestle with ourselves.
它用起来很简单这是因为Angular帮我们处理了大多数重复、单调的任务,这让我们可以不必亲自操刀、身陷其中。
它用起来很简单这是因为Angular处理了大多数重复、单调的任务这让我们可以不必亲自操刀、身陷其中。
We'll discuss and learn to build the following template-driven form:
@ -100,15 +100,16 @@ figure.image-display
Here at the *Hero Employment Agency* we use this form to maintain personal information about the
heroes in our stable. Every hero needs a job. It's our company mission to match the right hero with the right crisis!
这里是*英雄职业介绍所*,我们使用这个表单来维护候选英雄们的个人信息。每个英雄都需要一份工作。我们公司的任务就是让适当的英雄去解决它/她所擅长应对的危机!
这里是*英雄职业介绍所*,使用这个表单来维护候选英雄们的个人信息。每个英雄都需要一份工作。
公司的任务就是让适当的英雄去解决它/她所擅长应对的危机!
Two of the three fields on this form are required. Required fields have a green bar on the left to make them easy to spot.
表单中的三个字段,其中两个是必填的。必填的字段在左侧个绿色的竖条,方便用户分辨哪些是必填项。
表单中的三个字段,其中两个是必填的。必填的字段在左侧有个绿色的竖条,方便用户分辨哪些是必填项。
If we delete the hero name, the form displays a validation error in an attention grabbing style:
如果我们删除了英雄的名字,表单就会用一种引人注目的样式把验证错误显示出来。
如果删除了英雄的名字,表单就会用醒目的样式把验证错误显示出来。
figure.image-display
img(src="/resources/images/devguide/forms/hero-form-2.png" width="400px" alt="无效!名字是必填项")
@ -121,12 +122,12 @@ figure.image-display
.l-sub-section
p We'll customize the colors and location of the "required" bar with standard CSS.
p 我们将使用标准CSS来定制“必填”条的颜色和位置。
p 稍后,会使用标准 CSS 来定制“必填”条的颜色和位置。
:marked
We will build this form in the following sequence of small steps
我们将按照一系列很小的步骤来构建此表单:
按下面的步骤,一点一点构建此表单:
1. Create the `Hero` model class
@ -171,37 +172,37 @@ figure.image-display
Create a new project folder (`angular-forms`) and follow the steps in the [QuickStart](../quickstart.html).
创建一个新的项目文件夹 (`angular-forms`),并且完成[“快速起步”](../quickstart.html)中的步骤。
创建新的项目文件夹 (`angular-forms`),并且完成[“快速起步”](../quickstart.html)中的步骤。
include ../_quickstart_repo
:marked
## Create the Hero Model Class
## 创建一个Hero模型类
## 创建Hero模型类
As users enter form data, we capture their changes and update an instance of a model.
We can't layout the form until we know what the model looks like.
当用户输入表单数据时,需要捕获它们的变化,并更新到模型的一个实例中。
当用户输入表单数据时,需要捕获它们的变化,并更新到模型的实例中。
除非知道模型里有什么,否则无法设计表单的布局。
A model can be as simple as a "property bag" that holds facts about a thing of application importance.
That describes well our `Hero` class with its three required fields (`id`, `name`, `power`)
and one optional field (`alterEgo`).
最简单的模型个“属性包”,用来存放应用中一件事物的事实。
最简单的模型是个“属性包”,用来存放应用中一件事物的事实。
这里使用三个必备字段 (`id`、`name`、`power`),和一个可选字段 (`alterEgo`译注中文含义第二人格比如X战警中的Jean/黑凤凰)。
Create a new file in the app folder called `hero.ts` and give it the following class definition:
在应用文件夹中创建一个`hero.ts`文件,并且写入下列类定义内容:
在应用文件夹中创建`hero.ts`文件,并且写入下列类定义内容:
+makeExample('forms/ts/app/hero.ts', null, 'app/hero.ts')
:marked
It's an anemic model with few requirements and no behavior. Perfect for our demo.
这是一个少量需求和零行为的贫血模型。对我们的演示来说很完美。
这是一个少量需求和零行为的贫血模型。对演示来说很完美。
The TypeScript compiler generates a public field for each `public` constructor parameter and
assigns the parameters value to that field automatically when we create new heroes.
@ -210,11 +211,11 @@ include ../_quickstart_repo
The `alterEgo` is optional and the constructor lets us omit it; note the (?) in `alterEgo?`.
`alterEgo`是可选的,构造函数允许我们省略它,注意`alterEgo?`中的问号 (?)。
`alterEgo`是可选的,调用构造函数时可省略,注意`alterEgo?`中的问号 (?)。
We can create a new hero like this:
我们可以像这样创建一个新英雄:
可以像这样创建新英雄:
code-example(format="").
let myHero = new Hero(42, 'SkyDog',
'Fetch any object at any distance',
@ -226,26 +227,26 @@ code-example(format="").
:marked
## Create a Form component
## 创建一个表单组件
## 创建表单组件
An Angular form has two parts: an HTML-based template and a code-based Component to handle data and user interactions.
每个Angular表单分为两部分基于HTML的模板和基于代码的组件。组件用来处理数据和用户交互。
Angular 表单分为两部分:基于 HTML 的模板和基于代码的组件。组件用来处理数据和用户交互。
We begin with the Component because it states, in brief, what the Hero editor can do.
我们从组件开始,是因为它能够简要说明英雄编辑器能做什么。
先从组件开始,是因为它可以简要说明英雄编辑器能做什么。
Create a new file called `hero-form.component.ts` and give it the following definition:
创建一个名叫`hero-form.component.ts`的文件,并且放进下列定义:
创建名叫`hero-form.component.ts`的文件,放进下列定义:
+makeExample('forms/ts/app/hero-form.component.ts', 'first', 'app/hero-form.component.ts')
:marked
Theres nothing special about this component, nothing form-specific, nothing to distinguish it from any component we've written before.
组件没有什么特别的地方,没有表单相关的东西,与之前写过的组件没什么不同。
这个组件没有什么特别的地方,没有表单相关的东西,与之前写过的组件没什么不同。
Understanding this component requires only the Angular concepts weve learned in previous chapters
@ -253,7 +254,7 @@ code-example(format="").
1. We import the `Component` decorator from the Angular library as we usually do.
像往常一样,我们从 Angular 库中导入`Component`装饰器。
像往常一样,从 Angular 库中导入`Component`装饰器。
1. We import the `Hero` model we just created.
@ -277,30 +278,30 @@ code-example(format="").
parent component. None of this concerns us now and these future changes won't affect our form.
为`model`和`powers`定义了供演示用的假数据。
将来,可以注入一个服务来获取和保存真实数据,
将来,可以注入服务来获取和保存真实数据,
或者暴露这些属性为[输入与输出属性](./template-syntax.html#inputs-outputs),绑定到父组件上。
我们目前不关心这些,因为这些未来的变化不会影响到我们的表单。
不关心这些,因为这些未来的变化不会影响到表单。
1. We threw in a `diagnostic` property at the end to return a JSON representation of our model.
It'll help us see what we're doing during our development; we've left ourselves a cleanup note to discard it later.
我们在最后增加一个`diagnostic`属性它返回这个模型的JSON形式。
在开发过程中,它用于调试,最后清理时我们会丢弃它。
在最后增加`diagnostic`属性它返回这个模型的JSON形式。
在开发过程中,它用于调试,最后清理时会丢弃它。
Why don't we write the template inline in the component file as we often do
elsewhere in the Developer Guide?
这次我们为什么不像在开发指南其它地方那样,以内联的方式把模板写在组件文件中呢?
这次为什么不像在开发指南其它地方那样,以内联的方式把模板写在组件文件中呢?
There is no “right” answer for all occasions. We like inline templates when they are short.
Most form templates won't be short. TypeScript and JavaScript files generally aren't the best place to
write (or read) large stretches of HTML and few editors are much help with files that have a mix of HTML and code.
We also like short files with a clear and obvious purpose like this one.
没有什么答案在所有场合都总是“正确”的。当内联模板足够短的时候,我们更喜欢用它
没有什么答案在所有场合都总是“正确”的。当模板足够短的时候,内联形式更招人喜欢
但大多数的表单模板都不短。通常TypeScript 和 JavaScript 文件不是写(读)大型 HTML 的好地方,
而且没有几个编辑器能对混写的 HTML 和代码提供足够的帮助。
我们还是喜欢清晰明确的短文件,像这个一样。
我们还是喜欢内容清晰、目标明确的短文件,像这个一样。
We made a good choice to put the HTML template elsewhere.
We'll write that template in a moment. Before we do, we'll take a step back
@ -344,19 +345,19 @@ code-example(format="").
1. We add the `FormsModule` to the list of `imports` defined in the `ngModule` decorator. This gives our application
access to all of the template-driven forms features, including `ngModel`.
把`FormsModule`添加到`ngModule`装饰器的`imports`列表中。使应用能访问模板驱动表单的所有特性,包括`ngModel`。
把`FormsModule`添加到`ngModule`装饰器的`imports`列表中,这样应用就能访问模板驱动表单的所有特性,包括`ngModel`。
1. We add the `HeroFormComponent` to the list of `declarations` defined in the `ngModule` decorator. This makes
the `HeroFormComponent` component visible throughout this module.
把`HeroFormComponent`添加到`ngModule`装饰器的`declarations`列表中使`HeroFormComponent`组件在整个模块中可见。
把`HeroFormComponent`添加到`ngModule`装饰器的`declarations`列表中使`HeroFormComponent`组件在整个模块中可见。
.alert.is-important
:marked
If a component, directive, or pipe belongs to a module in the `imports` array, _DON'T_ declare it in the `declarations` array.
If you wrote it and it should belong to this module, _DO_ declare it in the `declarations` array.
如果一个组件、指令或管道出现在模块的`imports`数组中_不要_把它声明在`declarations`数组中。
如果组件、指令或管道出现在模块的`imports`数组中_不要_把它声明在`declarations`数组中。
如果它是你自己写的并且属于当前模块_就要_把它声明在`declarations`数组中。
.l-main-section
@ -367,7 +368,7 @@ code-example(format="").
`app.component.ts` is the application's root component. It will host our new `HeroFormComponent`.
`app.component.ts`是应用的根组件,`HeroFormComponent`将被放在其中。
`app.component.ts`是应用的根组件,`HeroFormComponent`将被放在其中。
Replace the contents of the "QuickStart" version with the following:
@ -390,7 +391,7 @@ code-example(format="").
:marked
## Create an initial HTML Form Template
## 创建一个初始 HTML 表单模板
## 创建初始 HTML 表单模板
Create a new template file called `hero-form.component.html` and give it the following definition:
@ -411,11 +412,11 @@ code-example(format="").
We've got a *Submit* button at the bottom with some classes on it for styling.
我们在底部有一个 *Submit* 按钮,它有一些 CSS 样式类。
底部有个 *Submit* 按钮,具有一些 CSS 样式类。
**We are not using Angular yet**. There are no bindings. No extra directives. Just layout.
**我们还没有用到Angular**。没有绑定,没有额外的指令,只有布局。
**还没有真正用到Angular**。没有绑定,没有额外的指令,只有布局。
The `container`, `form-group`, `form-control`, and `btn` classes
come from [Twitter Bootstrap](http://getbootstrap.com/css/). Purely cosmetic.
@ -423,8 +424,7 @@ code-example(format="").
Hey, what's a form without a little style!
`container`、`form-group`、`form-control`和`btn`类来自 [Twitter Bootstrap](http://getbootstrap.com/css/)。纯粹是装饰。
我们使用 Bootstrap 来美化我们的表单。
嘿,一点样式都没有的表单算个啥!
我们使用 Bootstrap 来美化表单。嘿,一点样式都没有的表单算个啥!
.callout.is-important
header Angular Forms Do Not Require A Style Library
@ -442,13 +442,13 @@ code-example(format="").
:marked
Let's add the stylesheet.
我们来添加样式表。
添加样式表。
ol
li
p Open a terminal window in the application root folder and enter the command:
p 在应用的根目录下打开一个终端窗口,敲如下命令:
p 在应用的根目录下打开终端窗口,输入如下命令:
code-example(language="html" escape="html").
npm install bootstrap --save
@ -469,15 +469,15 @@ ol
Our hero may choose one super power from a fixed list of Agency-approved powers.
We maintain that list internally (in `HeroFormComponent`).
英雄可以从认证过的固定列表中选择一项超能力。
我们在`HeroFormComponent`中内部维护这个列表
英雄可以从认证过的固定列表中选择一项超能力。
这个列表位于`HeroFormComponent`中
We'll add a `select` to our
form and bind the options to the `powers` list using `ngFor`,
a technique we might have seen before in the [Displaying Data](./displaying-data.html) chapter.
在表单中添加`select`,用`ngFor`把`powers`列表绑定到列表选项。
前面我们应该在[显示数据](./displaying-data.html)一章中见过`ngFor`。
我们在之前的[显示数据](./displaying-data.html)一章中见过`ngFor`。
Add the following HTML *immediately below* the *Alter Ego* group.
@ -489,8 +489,8 @@ ol
The `p` template input variable is a different power in each iteration;
we display its name using the interpolation syntax with the double-curly-braces.
我们为列表中的每一项超能力渲染出一个`<option>`标签。
模板输入变量`p`在每个迭代指向一个不同的超能力,使用双花括号插值表达式语法来显示它的名称。
列表中的每一项超能力都会渲染成`<option>`标签。
模板输入变量`p`在每个迭代指向不同的超能力,使用双花括号插值表达式语法来显示它的名称。
<a id="ngModel"></a>
.l-main-section
@ -561,7 +561,7 @@ figure.image-display
The diagnostic is evidence that we really are flowing values from the input box to the model and
back again. **That's two-way data binding!**
诊断信息是一个证据,表明数据确实从输入框流动到模型,再反向流动回来。**这就是双向数据绑定!**
诊断信息可以证明,数据确实从输入框流动到模型,再反向流动回来。**这就是双向数据绑定!**
Notice that we also added a `name` attribute to our `<input>` tag and set it to "name"
which makes sense for the hero's name. Any unique value will do, but using a descriptive name is helpful.
@ -602,16 +602,16 @@ figure.image-display
- Each input element has an `id` property that is used by the `label` element's `for` attribute
to match the label to its input control.
个 input 元素都有一个`id`属性,`label`元素的`for`属性用它来匹配到对应的输入控件。
每个 input 元素都有`id`属性,`label`元素的`for`属性用它来匹配到对应的输入控件。
- Each input element has a `name` property that is required by Angular Forms to register the control with the form.
个 input 元素都有一个`name`属性Angular 表单用它注册控件。
每个 input 元素都有`name`属性Angular 表单用它注册控件。
:marked
If we ran the app right now and changed every Hero model property, the form might display like this:
如果现在运行本应用修改Hero模型的每个属性表单看起来像这样
如果现在运行本应用,修改 Hero 模型的每个属性,表单看起来像这样:
figure.image-display
img(src="/resources/images/devguide/forms/ng-model-in-action-2.png" width="400px" alt="ngModel in super action")
:marked
@ -636,7 +636,7 @@ figure.image-display
The punctuation in the binding syntax, <span style="font-family:courier"><b>[()]</b></span>, is a good clue to what's going on.
绑定语法中的<span style="font-family:courier"><b>[()]</b></span>是一个很好的线索。
绑定语法中的<span style="font-family:courier"><b>[()]</b></span>是很好的线索。
In a Property Binding, a value flows from the model to a target property on screen.
We identify that target property by surrounding its name in brackets, <span style="font-family:courier"><b>[]</b></span>.
@ -689,7 +689,7 @@ figure.image-display
模板表达式中的另一个古怪之处是`model.name = $event`。
之前看到的`$event`对象来自DOM事件。
但`ngModelChange`属性不会生成DOM事件 —— 它是Angular `EventEmitter`类型的属性,当它触发时,
它返回的是输入框的值 —— 也正是我们希望赋给模型`name`属性的值。
它返回的是输入框的值 —— 也正是希望赋给模型`name`属性的值。
Nice to know but is it practical? We almost always prefer `[(ngModel)]`.
We might split the binding if we had to do something special in
@ -711,7 +711,7 @@ figure.image-display
A form isn't just about data binding. We'd also like to know the state of the controls on our form.
表单不仅是关于数据绑定的。我们还希望知道表单中各个控件的状态。
表单不仅是关于数据绑定的。我们还知道表单中各个控件的状态。
Using `ngModel` in a form gives us more than just two way data binding. It also tells us if the user touched the control, if the value changed, or if the value became invalid.
@ -769,7 +769,7 @@ table
Let's add a temporary [template reference variable](./template-syntax.html#ref-vars) named **spy**
to the "Name" `<input>` tag and use the spy to display those classes.
我们往姓名`<input>`标签上添加一个名叫 **spy** 的临时[模板引用变量](./template-syntax.html#local-vars)
往姓名`<input>`标签上添加名叫 **spy** 的临时[模板引用变量](./template-syntax.html#local-vars)
然后用这个 spy 来显示它上面的所有 CSS 类。
+makeExample('forms/ts/app/hero-form.component.html', 'ngModelName-2','app/hero-form.component.html (excerpt)')(format=".")
@ -815,7 +815,7 @@ figure.image-display
strong visual signal when the data are invalid and we want to mark required fields.
So we add custom CSS for visual feedback.
(`ng-valid` | `ng-invalid`)这一对是我们最感兴趣的。当数据变得无效时,我们希望发出一个强力的视觉信号,
(`ng-valid` | `ng-invalid`)这一对是我们最感兴趣的。当数据变得无效时,我们希望发出强力的视觉信号,
还想要标记出必填字段。可以通过加入自定义 CSS 来提供视觉反馈。
**Delete** the `#spy` template reference variable and `TODO` as they have served their purpose.
@ -850,7 +850,7 @@ figure.image-display
We update the `<head>` of the `index.html` to include this style sheet.
我们更新`index.html`中的`<head>`来包含这个样式表。
更新`index.html`中的`<head>`来包含这个样式表。
+makeExample('forms/ts/index.html', 'styles', 'index.html (节选)')(format=".")
:marked
## Show and Hide Validation Error messages
@ -882,11 +882,11 @@ figure.image-display
1. a [template reference variable](./template-syntax.html#ref-vars)
一个[模板引用变量](./template-syntax.html#ref-vars)
[模板引用变量](./template-syntax.html#ref-vars)
1. the "*is required*" message in a nearby `<div>` which we'll display only if the control is invalid.
“is required”消息放在邻近的一个`<div>`元素中,只有当控件无效时,才显示它。
“is required”消息放在邻近的`<div>`元素中,只有当控件无效时,才显示它。
Here's how we do it for the *name* input box:
@ -931,16 +931,16 @@ figure.image-display
we'll see the error message immediately, before we've done anything.
这种用户体验取决于开发人员的选择。有些人会希望任何时候都显示这条消息。
如果忽略了`pristine`状态,我们就会只在值有效时隐藏此消息。
如果往这个组件中传入一个全新(空)的英雄,或者一个无效的英雄,将立刻看到错误信息 —— 虽然我们还啥都没做。
如果忽略了`pristine`状态,就会只在值有效时隐藏此消息。
如果往这个组件中传入全新(空)的英雄,或者无效的英雄,将立刻看到错误信息 —— 虽然我们还啥都没做。
Some folks find that behavior disconcerting. They only want to see the message when the user makes an invalid change.
Hiding the message while the control is "pristine" achieves that goal.
We'll see the significance of this choice when we [add a new hero](#new-hero) to the form.
有些人会为这种行为感到不安。它们希望只有在用户做出一个无效的更改时才显示这个消息。
有些人会为这种行为感到不安。它们希望只有在用户做出无效的更改时才显示这个消息。
如果当控件是“全新”状态时也隐藏消息,就能达到这个目的。
在往表单中[添加一个新英雄](#new-hero)时,将看到这种选择的重要性。
在往表单中[添加新英雄](#new-hero)时,将看到这种选择的重要性。
The Hero *Alter Ego* is optional so we can leave that be.
@ -967,7 +967,7 @@ figure.image-display
We place a "New Hero" button at the bottom of the form and bind its click event to a component method.
我们希望在这个表单中添加新的英雄。
在表单的底部放一个“New Hero新增英雄”按钮并把它的点击事件绑定到组件方法。
在表单的底部放“New Hero新增英雄”按钮并把它的点击事件绑定到组件方法。
+makeExample('forms/ts/app/hero-form.component.html',
'new-hero-button',
'app/hero-form.component.html (新增英雄按钮)')
@ -989,8 +989,8 @@ figure.image-display
Enter a name and click *New Hero* again.
This time we see an error message! Why? We don't want that when we display a new (empty) hero.
输入一个名字,再次点击 *New Hero* 按钮。
这次,出现了错误信息!为什么?我们不希望显示一个新(空)的英雄时,出现错误信息。
输入名字,再次点击 *New Hero* 按钮。
这次,出现了错误信息!为什么?我们不希望显示新(空)的英雄时,出现错误信息。
Inspecting the element in the browser tools reveals that the *name* input box is no longer pristine.
Replacing the hero *did not restore the pristine state* of the control.
@ -1010,9 +1010,9 @@ figure.image-display
We add an `active` flag to the component, initialized to `true`. When we add a new hero,
we toggle `active` false and then immediately back to true with a quick `setTimeout`.
可以使个小花招来重置表单控件。
给组件添加一个`active`标记,初始化为`true`。当添加一个新的英雄时,把`active`标记设置为`false`
再通过一个快速的`setTimeout`函数迅速把它设置回`true`。
可以用个小花招来重置表单控件。
给组件添加`active`标记,初始化为`true`。当添加新的英雄时,把`active`标记设置为`false`
再通过快速的`setTimeout`函数迅速把它设置回`true`。
+makeExample('forms/ts/app/hero-form.component.ts',
'new-hero',
'app/hero-form.component.ts (新增英雄 - 最终版)')(format=".")
@ -1056,7 +1056,7 @@ figure.image-display
and bind it to the `HeroFormComponent.submit()` method with an event binding
仅仅触发“表单提交”在目前是没用的。
要让它有用,我们还要用另一个 Angular 指令更新`<form>`标签 —— `NgSubmit`
要让它有用,还要用另外的 Angular 指令更新`<form>`标签 —— `NgSubmit`
并且通过事件绑定把它绑定到`HeroFormComponent.submit()`方法。
+makeExample('forms/ts/app/hero-form.component.html', 'ngSubmit')(format=".")
@ -1064,7 +1064,7 @@ figure.image-display
We slipped in something extra there at the end! We defined a
template reference variable, **`#heroForm`**, and initialized it with the value, "ngForm".
上面代码的最后出现一些额外的东西!定义了一个模板引用变量**`#heroForm`**,并初始化为"ngForm"。
上面代码的最后出现一些额外的东西!定义了模板引用变量**`#heroForm`**,并初始化为"ngForm"。
The variable `heroForm` is now a reference to the `NgForm` directive that governs the form as a whole.
@ -1092,7 +1092,7 @@ figure.image-display
`NgForm`指令为`form`元素扩充了额外的特性。
它持有通过`ngModel`指令和`name`属性为各个元素创建的那些控件,并且监视它们的属性变化,包括有效性。
它还有自己的`valid`属性,只有当*每一个被包含的控件*都有效时,它才有效。
它还有自己的`valid`属性,只有当*其中所有控件*都有效时,它才有效。
:marked
Later in the template we bind the button's `disabled` property to the form's over-all validity via
@ -1122,7 +1122,7 @@ figure.image-display
1. Define a template reference variable on the (enhanced) form element
定义一个模板引用变量放在强化过的form 元素上
定义模板引用变量放在强化过的form 元素上
2. Reference that variable in a button some 50 lines away.
@ -1147,8 +1147,8 @@ figure.image-display
If you're not interested, you can skip to the chapter's conclusion
and not miss a thing.
对演示来说,这是一个平淡的收场。老实说,即使让它更出彩,也无法教给我们任何关于表单的新知识。
但这是锻炼我们新学到的绑定技能的好机会。
对演示来说,这个收场很平淡的。老实说,即使让它更出彩,也无法教给我们任何关于表单的新知识。
但这是练习新学到的绑定技能的好机会。
如果你不感兴趣,可以跳到本章的总结部分,不用担心错失任何东西。
:marked
@ -1170,7 +1170,7 @@ figure.image-display
the `submitted` property is false until we submit the form,
as this fragment from the `HeroFormComponent` reminds us:
主表单从一开始就是可见的,因为`submitted`属性是false直到我们提交了这个表单。
主表单从一开始就是可见的,因为`submitted`属性是false直到提交了这个表单。
来自`HeroFormComponent`的代码片段告诉了我们这一点:
+makeExample('forms/ts/app/hero-form.component.ts', 'submitted')(format=".")
@ -1179,26 +1179,26 @@ figure.image-display
When we click the Submit button, the `submitted` flag becomes true and the form disappears
as planned.
我们点击 Submit 按钮时,`submitted`标志会变成 true并且表单像预想中一样消失了。
当点击 Submit 按钮时,`submitted`标志会变成 true并且表单像预想中一样消失了。
Now we need to show something else while the form is in the submitted state.
Add the following block of HTML below the `<div>` wrapper we just wrote:
现在,当表单处于已提交状态时,需要显示一些别的东西。
我们刚刚写的`<div>`包装下方添加下列HTML块
在刚刚写的`<div>`包装下方添加下列HTML块
+makeExample('forms/ts/app/hero-form.component.html', 'submitted', 'app/hero-form.component.html (节选)')
:marked
There's our hero again, displayed read-only with interpolation bindings.
This slug of HTML only appears while the component is in the submitted state.
我们的英雄又来了,它通过插值表达式绑定显示为只读内容。
英雄又出现了,它通过插值表达式绑定显示为只读内容。
这一小段 HTML 只在组件处于已提交状态时才会显示。
We added an Edit button whose click event is bound to an expression
that clears the `submitted` flag.
添加了一个“Edit编辑”按钮它的click事件绑定到一个表达式,用于清除`submitted`标志。
添加了“Edit编辑”按钮将click事件绑定到表达式,用于清除`submitted`标志。
When we click it, this block disappears and the editable form reappears.