translate: form-validation to line 486
This commit is contained in:
parent
fb4aa6a7a0
commit
13a3074d6c
|
@ -91,44 +91,76 @@ a#template1
|
|||
|
||||
:marked
|
||||
Note the following:
|
||||
|
||||
请注意一下几点:
|
||||
|
||||
- The `<input>` element carries the HTML validation attributes: `required`, `minlength`, and `maxlength`.
|
||||
|
||||
- `<input>`元素具有HTML验证属性:`required`、`minlength`、和 `maxlength`。
|
||||
|
||||
- We set the `name` attribute of the input box to `"name"` so Angular can track this input element and associate it
|
||||
with an Angular form control called `name` in its internal control model.
|
||||
|
||||
- 我们设置输入框的`name`属性为`"name"`,这样Angular可以跟踪这个输入元素,并将其内部控制器模型的一个名为`name`的Angular表单控制关联起来。
|
||||
|
||||
- We use the `[(ngModel)]` directive to two-way data bind the input box to the `hero.name` property.
|
||||
|
||||
- 我们使用`[(ngModel)]`指令,将输入框双向数据绑定到`hero.name`属性。
|
||||
|
||||
- We set a template variable (`#name`) to the value `"ngModel"` (always `ngModel`).
|
||||
This gives us a reference to the Angular `NgModel` directive
|
||||
associated with this control that we can use _in the template_
|
||||
to check for control states such as `valid` and `dirty`.
|
||||
|
||||
- 我们将模板变量(`#name`)赋值为`"ngModel"` (总是 `ngModel`)。
|
||||
它为我们提供了与这个控制器关联的Angular `NgModel`指令的引用,我们在模板中使用它,以检查控制器状态,比如`valid`和`dirty`。
|
||||
|
||||
- The `*ngIf` on `<div>` element reveals a set of nested message `divs` but only if there are "name" errors and
|
||||
the control is either `dirty` or `touched`.
|
||||
|
||||
- `<div>`元素的`*ngIf`揭露了一套嵌套消息`divs`,但是只在有“name”错误和控制器为`dirty`或者`touched`。
|
||||
|
||||
- Each nested `<div>` can present a custom message for one of the possible validation errors.
|
||||
We've prepared messages for `required`, `minlength`, and `maxlength`.
|
||||
|
||||
- 每个嵌套的`<div>`为其中一个可能出现的验证错误显示一条自定义消息。我们已经为`required`、`minlength`、和 `maxlength`准备了消息。
|
||||
|
||||
The full template repeats this kind of layout for each data entry control on the form.
|
||||
|
||||
整个模板为表单上的每种数据输入控制器重复这种布局。
|
||||
|
||||
.l-sub-section
|
||||
:marked
|
||||
#### Why check _dirty_ and _touched_?
|
||||
|
||||
### 为何检查**dirty**和**touched**?
|
||||
|
||||
We shouldn't show errors for a new hero before the user has had a chance to edit the value.
|
||||
The checks for `dirty` and `touched` prevent premature display of errors.
|
||||
|
||||
当用户创建一个新英雄时,在还没有机会输入之前,我们不应该显示任何错误。
|
||||
检查`dirty`和`touched`防止了这种过早的错误显示。
|
||||
|
||||
Learn about `dirty` and `touched` in the [Forms](../guide/forms.html) chapter.
|
||||
|
||||
参见[表单](../guide/forms.html)章,学习关于`dirty`和`touched`的知识。
|
||||
:marked
|
||||
The component class manages the hero model used in the data binding
|
||||
as well as other code to support the view.
|
||||
|
||||
组件类管理用于数据绑定的英雄模型,它还有其他支持视图的代码。
|
||||
|
||||
+makeExample('cb-form-validation/ts/app/template/hero-form-template1.component.ts','class','template/hero-form-template1.component.ts (class)')
|
||||
|
||||
:marked
|
||||
Use this template-driven validation technique when working with static forms with simple, standard validation rules.
|
||||
|
||||
在处理简单的、拥有标准验证规则的静态表单时,使用这种模板驱动验证方法。
|
||||
|
||||
Here are the complete files for the first version of `HeroFormTemplateCompononent` in the template-driven approach:
|
||||
|
||||
下面是第一个版本的使用模板驱动方法的`HeroFormTemplateComponent`:
|
||||
|
||||
+makeTabs(
|
||||
`cb-form-validation/ts/app/template/hero-form-template1.component.html,
|
||||
cb-form-validation/ts/app/template/hero-form-template1.component.ts`,
|
||||
|
@ -141,21 +173,36 @@ a#template2
|
|||
:marked
|
||||
## Template-Driven Forms with validation messages in code
|
||||
|
||||
## 验证消息在代码中的模板驱动表单
|
||||
|
||||
While the layout is straightforward,
|
||||
there are obvious shortcomings with the way we handle validation messages:
|
||||
|
||||
虽然布局很直观,但是我们处理验证消息的方法有明显的缺陷:
|
||||
|
||||
* It takes a lot of HTML to represent all possible error conditions.
|
||||
This gets out of hand when there are many controls and many validation rules.
|
||||
|
||||
* 它使用了很多HTML来表现所有可能出现的错误情况。
|
||||
如果有太多控制器和太多验证规则,我们就失去了控制。
|
||||
|
||||
* We're not fond of so much JavaScript logic in HTML.
|
||||
|
||||
* 我们不喜欢在HTML里面插入这么多JavaScript。
|
||||
|
||||
* The messages are static strings, hard-coded into the template.
|
||||
We often require dynamic messages that we should shape in code.
|
||||
|
||||
* 这些消息是静态的字符串,被硬编码到模板中。我们通常要求在代码中可以塑造的动态消息。
|
||||
|
||||
We can move the logic and the messages into the component with a few changes to
|
||||
the template and component.
|
||||
|
||||
只需要对模板和组件做出一些修改,我们可以将逻辑和消息移到组件中。
|
||||
|
||||
Here's the hero name again, excerpted from the revised template ("Template 2"), next to the original version:
|
||||
|
||||
下面也是关于英雄名字的控制器,从修改后的模板("Template 2")中抽取出来,与原来的版本相比:
|
||||
+makeTabs(
|
||||
`cb-form-validation/ts/app/template/hero-form-template2.component.html,
|
||||
cb-form-validation/ts/app/template/hero-form-template1.component.html`,
|
||||
|
@ -165,46 +212,87 @@ a#template2
|
|||
|
||||
:marked
|
||||
The `<input>` element HTML is almost the same. There are noteworthy differences:
|
||||
- The hard-code error message `<divs>` are gone.
|
||||
|
||||
`<input>`元素的HTML几乎一样。但是下列有值得注意的区别:
|
||||
|
||||
- The hard-code error message `<div>` are gone.
|
||||
|
||||
- 硬编码的错误消息`<div>`消失了。
|
||||
|
||||
- There's a new attribute, `forbiddenName`, that is actually a custom validation directive.
|
||||
It invalidates the control if the user enters "bob" anywhere in the name ([try it](#live-example)).
|
||||
We discuss [custom validation directives](#custom-validation) later in this cookbook.
|
||||
|
||||
- 添加了一个新属性`forbiddenName`,它实际上是一个自定义验证指令。
|
||||
如果用户名字中的任何地方输入“bob”,该指令变将控制器标记为无效([试试](#live-example))。
|
||||
我们在本烹饪书后面介绍了[自定义验证指令](#custom-validation)。
|
||||
|
||||
- The `#name` template variable is gone because we no longer refer to the Angular control for this element.
|
||||
|
||||
- 模板变量`#name`消失了,因为我们不再需要为这个元素引用Angular控制器。
|
||||
|
||||
- Binding to the new `formErrors.name` property is sufficent to display all name validation error messages.
|
||||
|
||||
- 绑定到新的`formErrors.name`属性,就可以处理所有名字验证错误信息了。
|
||||
|
||||
#### Component class
|
||||
|
||||
#### 组件类
|
||||
|
||||
The original component code stays the same.
|
||||
We _added_ new code to acquire the Angular form control and compose error messages.
|
||||
|
||||
原来的组件代码还是一样。我们**添加**了新的代码,来获取Angular表单控制器和撰写错误信息。
|
||||
|
||||
The first step is to acquire the form control that Angular created from the template by querying for it.
|
||||
|
||||
第一步是获取Angular通过查询模板而生成的表单控制器。
|
||||
|
||||
Look back at the top of the component template where we set the
|
||||
`#heroForm` template variable in the `<form>` element:
|
||||
|
||||
回头看组件模板顶部,我们在`<form>`元素中设置`#heroForm`模板变量:
|
||||
|
||||
+makeExample('cb-form-validation/ts/app/template/hero-form-template1.component.html','form-tag','template/hero-form-template1.component.html (form tag)')(format='.')
|
||||
|
||||
:marked
|
||||
The `heroForm` variable is a reference to the control model that Angular derived from the template.
|
||||
We tell Angular to inject that model into the component class's `currentForm` property using a `@ViewChild` query:
|
||||
|
||||
`heroFrom`变量是Angular从模板衍生出来的控制模型的引用。
|
||||
我们利用`@ViewChild`来告诉Angular注入这个模型到组件类的`currentForm`属性:
|
||||
|
||||
+makeExample('cb-form-validation/ts/app/template/hero-form-template2.component.ts','view-child','template/hero-form-template2.component.ts (heroForm)')(format='.')
|
||||
|
||||
:marked
|
||||
Some observations:
|
||||
|
||||
一些细节:
|
||||
|
||||
- Angular `@ViewChild` queries for a template variable when you pass it
|
||||
the name of that variable as a string (`'heroForm'` in this case).
|
||||
|
||||
- Angular的`@ViewChild`使用传入的模板变量的字符串名字(这里是`'heroForm'`),来查询对应的模板变量。
|
||||
|
||||
- The `heroForm` object changes several times during the life of the component, most notably when we add a new hero.
|
||||
We'll have to re-inspect it periodically.
|
||||
|
||||
- `heroForm`对象在组件的生命周期内变化了好几次,最值得注意的是当我们添加一个新英雄时的变化。我们必须定期重新检测它。
|
||||
|
||||
- Angular calls the `ngAfterViewChecked` [lifecycle hook method](../guide/lifecycle-hooks.html#afterview)
|
||||
when anything changes in the view.
|
||||
That's the right time to see if there's a new `heroForm` object.
|
||||
|
||||
- 当视图有任何变化时,Angular调用`ngAfterViewChecked`[生命周期钩子方法](../guide/lifecycle-hooks.html#afterview)。这是查看是否有新`heroForm`对象的最佳时机。
|
||||
|
||||
- When there _is_ a new `heroForm` model, we subscribe to its `valueChanged` _Observable_ property.
|
||||
|
||||
- 当出现新`heroForm`模型时,我们订阅它的`valueChanged`**可观察**属性。
|
||||
|
||||
The `onValueChanged` handler looks for validation errors after every user keystroke.
|
||||
|
||||
`onValueChanged`处理器在每次用户键入后查找验证错误。
|
||||
|
||||
+makeExample('cb-form-validation/ts/app/template/hero-form-template2.component.ts','handler','template/hero-form-template2.component.ts (handler)')(format='.')
|
||||
|
||||
:marked
|
||||
|
@ -212,96 +300,191 @@ a#template2
|
|||
The `data` object passed into the handler contains the current element values.
|
||||
The handler ignores them. Instead, it iterates over the fields of the component's `formErrors` object.
|
||||
|
||||
`onValueChanged`处理器拦截用户数据输入。
|
||||
包含当前元素值得`data`对象被传入处理器。
|
||||
处理器忽略它们。相反,它迭代组件的`formErrors`对象。
|
||||
|
||||
The `formErrors` is a dictionary of the hero fields that have validation rules and their current error messages.
|
||||
Only two hero properties have validation rules, `name` and `power`.
|
||||
The messages are empty strings when the hero data are valid.
|
||||
|
||||
`formErrors`是一个词典,包含了拥有验证规则和当前错误消息的英雄控件。
|
||||
只有两个英雄属性有验证规则,`name`和`power`。
|
||||
当英雄数据有效时,这些消息的值为空字符串。
|
||||
|
||||
For each field, the handler
|
||||
|
||||
对于每个控件,这个处理器:
|
||||
|
||||
- clears the prior error message if any
|
||||
- acquires the field's corresponding Angular form control
|
||||
|
||||
- 如果有之前的错误信息,清楚它们
|
||||
|
||||
- acquires the field's corresponding Angular form control
|
||||
|
||||
- 获取控件对应的Angular表单控制器
|
||||
|
||||
- if such a control exists _and_ its been changed ("dirty") _and_ its invalid ...
|
||||
|
||||
- 如果这样的控制器存在,并且它被更新(“dirty”)**以及**它无效...
|
||||
|
||||
- the handler composes a consolidated error message for all of the control's errors.
|
||||
|
||||
- 处理器便为所有控制器的错误合成一条错误消息。
|
||||
|
||||
We'll need some error messages of course, a set for each validated property, one message per validation rule:
|
||||
|
||||
很显然,我们需要一些错误消息,每个验证的属性都需要一套,每个验证规则需要一条消息:
|
||||
|
||||
+makeExample('cb-form-validation/ts/app/template/hero-form-template2.component.ts','messages','template/hero-form-template2.component.ts (messages)')(format='.')
|
||||
:marked
|
||||
Now every time the user makes a change, the `onValueChanged` handler checks for validation errors and produces messages accordingly.
|
||||
|
||||
现在,每次用户作出变化时,`onValueChanged`处理器检查验证错误并按情况发出错误消息。
|
||||
|
||||
### Is this an improvement?
|
||||
|
||||
### 这是增强吗?
|
||||
|
||||
Clearly the template got substantially smaller while the component code got substantially larger.
|
||||
It's not easy to see the benefit when there are just three fields and only two of them have validation rules.
|
||||
|
||||
很显然,模板变得小多了,组件代码变得大多了。当只有三个控件并且其中只有两个有验证规则时,我们很难看出好处。
|
||||
|
||||
Consider what happens as we increase the number of validated fields and rules.
|
||||
In general, HTML is harder to read and maintain than code.
|
||||
The initial template was already large and threatening to get rapidly worse as we add more validation message `<divs>`.
|
||||
|
||||
假设增加需要验证的控件和规则后会怎么样。
|
||||
通常,HTML比代码更难阅读和维护。
|
||||
初始的模板已经很大了,如果我们添加更多验证消息`<div>`,它会迅速变得更大。
|
||||
|
||||
After moving the validation messaging to the component,
|
||||
the template grows more slowly and proportionally.
|
||||
Each field has approximately the same number of lines no matter its number of validation rules.
|
||||
The component also grows proportionally, at the rate of one line per validated field
|
||||
and one line per validation message.
|
||||
|
||||
将验证消息移到组件后,模板的增长变得更加缓慢,幅度也小一些。
|
||||
不管有多少个验证规则,每个控件的行数是差不多的。
|
||||
组件也按比例增长,每增加一个控件增加一行,每个验证消息一行。
|
||||
|
||||
Both trends are manageable.
|
||||
|
||||
两条线容易维护。
|
||||
|
||||
Now that the messages are in code, we have more flexibility. We can compose messages more intelligently.
|
||||
We can refactor the messages out of the component, perhaps to a service class that retrieves them from the server.
|
||||
In short, there are more opportunities to improve message handling now that text and logic have moved from template to code.
|
||||
|
||||
现在消息在代码中,我们有更多的灵活度。我们更加智能的撰写消息。
|
||||
我们可以将消息重构出组件,比如到一个服务类,从服务端获取消息。
|
||||
简而言之,有很多机会增强消息处理,因为文本和逻辑都已经从模板移到代码中。
|
||||
|
||||
### _FormModule_ and template-driven forms
|
||||
|
||||
### _FormModule_ 和模板驱动表单
|
||||
|
||||
Angular has two different forms modules — `FormsModule` and `ReactiveFormsModule` —
|
||||
that correspond with the two approaches to form development.
|
||||
Both modules come from the same `@angular/forms` library package.
|
||||
|
||||
Angular有两种不同的表单模块 - `FormsModule`和`ReactiveFormsModule` - 它们与表单开发的两种方法对应。
|
||||
两种模块都从同一个`@angular/forms`库。
|
||||
|
||||
We've been reviewing the "Template-driven" approach which requires the `FormsModule`
|
||||
Here's how we imported it in the `HeroFormTemplateModule`.
|
||||
|
||||
我们一直在探讨**模板驱动**方法,它需要`FormsModule`。下面是如何在`HeroFormTemplateModule`中导入它:
|
||||
|
||||
+makeExample('cb-form-validation/ts/app/template/hero-form-template.module.ts','','template/hero-form-template.module.ts')(format='.')
|
||||
.l-sub-section
|
||||
:marked
|
||||
We haven't talked about the `SharedModule` or its `SubmittedComponent` which appears at the bottom of every
|
||||
form template in this cookbook.
|
||||
|
||||
我们还没有讲`SharedModule`或者它的`SubmittedComponent`,它们出现在本烹饪书的每一个表单模板中。
|
||||
|
||||
They're not germane to the validation story. Look at the [live example](#live-example) if you're interested.
|
||||
|
||||
它们与表单验证没有紧密的关系。如果你感兴趣,参见[在线例子](#live-example)。
|
||||
|
||||
.l-main-section
|
||||
a#reactive
|
||||
:marked
|
||||
## Reactive Forms
|
||||
|
||||
## 响应式表单
|
||||
|
||||
In the template-driven approach, you markup the template with form elements, validation attributes,
|
||||
and `ng...` directives from the Angular `FormsModule`.
|
||||
At runtime, Angular interprets the template and derives its _form control model_.
|
||||
|
||||
在模板驱动方法中,你在模板中标出表单元素、验证属性和Angular`FormsModule`中的`ng...`指令。
|
||||
在运行时间,Angular解释模板并从**表单控制器模型**衍生它。
|
||||
|
||||
**Reactive Forms** takes a different approach.
|
||||
You create the form control model in code. You write the template with form elements
|
||||
and`form...` directives from the Angular `ReactiveFormsModule`.
|
||||
At runtime, Angular binds the template elements to your control model based on your instructions.
|
||||
|
||||
**响应式表单**采用不同的方法。
|
||||
你在代码中创建表单控制器模型,并用表单元素和来自Angular `ReactiveFormsModule`中的`form...`指令来编写模板。
|
||||
在运行时间,Angular根据你的指示绑定模板元素到你的控制器模型。
|
||||
|
||||
This approach requires a bit more effort. *You have to write the control model and manage it*.
|
||||
|
||||
这个方法需要做一些额外的工作。*你必须编写并管理控制器模型**
|
||||
|
||||
In return, you can
|
||||
|
||||
作为回报,你可以:
|
||||
|
||||
* add, change, and remove validation functions on the fly
|
||||
|
||||
* 随时添加、修改和删除验证功能
|
||||
|
||||
* manipulate the control model dynamically from within the component
|
||||
|
||||
* 在组件内动态操纵控制器模型
|
||||
|
||||
* [test](#testing) validation and control logic with isolated unit tests.
|
||||
|
||||
* 使用孤立单元测试来[测试](#testing)验证和控制器逻辑
|
||||
|
||||
The third cookbook sample re-writes the hero form in _reactive forms_ style.
|
||||
|
||||
第三个烹饪书例子用**响应式表单**风格重新编写英雄表格。
|
||||
|
||||
### Switch to the _ReactiveFormsModule_
|
||||
|
||||
### 切换到_ReactiveFormsModule_
|
||||
|
||||
The reactive forms classes and directives come from the Angular `ReactiveFormsModule`, not the `FormsModule`.
|
||||
The application module for the "Reactive Forms" feature in this sample looks like this:
|
||||
|
||||
响应式表单类和指令来自于Angular的`ReactiveFormsModule`,不是`FormsModule`。
|
||||
本例中,应用模块的“响应式表单”特性是这样的:
|
||||
|
||||
+makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.module.ts','','app/reactive/hero-form-reactive.module.ts')(format='.')
|
||||
:marked
|
||||
The "Reactive Forms" feature module and component are in the `app/reactive` folder.
|
||||
Let's focus on the `HeroFormReactiveComponent` there, starting with its template.
|
||||
|
||||
“响应式表单”特性模块和组件在`app/reactive`目录。
|
||||
让我们关注那里的`HeroFormReactiveComponent`,先看它的模板。
|
||||
|
||||
### Component template
|
||||
|
||||
## 组件模板
|
||||
|
||||
We begin by changing the `<form>` tag so that it binds the Angular `formGroup` directive in the template
|
||||
to the `heroForm` property in the component class.
|
||||
The `heroForm` is the control model that the component class builds and maintains.
|
||||
|
||||
我们先修改`<form>`标签,让Angular的`formGroup`指令绑定到组件类的`heroForm`属性。
|
||||
`heroForm`是组件类创建和维护的控制器模型。
|
||||
|
||||
+makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.html','form-tag')(format='.')
|
||||
:marked
|
||||
Then we modify the template HTML elements to match the _reactive forms_ style.
|
||||
|
|
Loading…
Reference in New Issue