translate: form-validation, done.
This commit is contained in:
		
							parent
							
								
									13a3074d6c
								
							
						
					
					
						commit
						9129f46f45
					
				| @ -74,7 +74,7 @@ a#template1 | |||||||
|    to the elements. Angular interprets those as well, adding validator functions to the control model. |    to the elements. Angular interprets those as well, adding validator functions to the control model. | ||||||
| 
 | 
 | ||||||
|    要验证用户输入,你添加[HTML验证属性](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)到元素中。 |    要验证用户输入,你添加[HTML验证属性](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)到元素中。 | ||||||
|    Angular拦截这些元素,添加验证器功能到控制模型中。 |    Angular拦截这些元素,添加验证器函数到控制模型中。 | ||||||
| 
 | 
 | ||||||
|    Angular exposes information about the state of the controls including  |    Angular exposes information about the state of the controls including  | ||||||
|    whether the user has "touched" the control or made changes and if the control values are valid. |    whether the user has "touched" the control or made changes and if the control values are valid. | ||||||
| @ -442,7 +442,7 @@ a#reactive | |||||||
| 
 | 
 | ||||||
|   * add, change, and remove validation functions on the fly |   * add, change, and remove validation functions on the fly | ||||||
| 
 | 
 | ||||||
|   * 随时添加、修改和删除验证功能 |   * 随时添加、修改和删除验证函数 | ||||||
| 
 | 
 | ||||||
|   * manipulate the control model dynamically from within the component |   * manipulate the control model dynamically from within the component | ||||||
| 
 | 
 | ||||||
| @ -489,6 +489,10 @@ a#reactive | |||||||
| :marked | :marked | ||||||
|   Then we modify the template HTML elements to match the _reactive forms_ style. |   Then we modify the template HTML elements to match the _reactive forms_ style. | ||||||
|   Here is the "name" portion of the template again, revised for reactive forms and compared with the template-driven version: |   Here is the "name" portion of the template again, revised for reactive forms and compared with the template-driven version: | ||||||
|  | 
 | ||||||
|  |   接下来,我们修改模板HTML元素,来匹配**响应式表单**样式。 | ||||||
|  |   下面又是“name”部分的模板,响应式表单修改版本和模板驱动版本的比较: | ||||||
|  | 
 | ||||||
| +makeTabs( | +makeTabs( | ||||||
|   `cb-form-validation/ts/app/reactive/hero-form-reactive.component.html,  |   `cb-form-validation/ts/app/reactive/hero-form-reactive.component.html,  | ||||||
|    cb-form-validation/ts/app/template/hero-form-template2.component.html`, |    cb-form-validation/ts/app/template/hero-form-template2.component.html`, | ||||||
| @ -498,39 +502,66 @@ a#reactive | |||||||
| 
 | 
 | ||||||
| :marked | :marked | ||||||
|   Key changes: |   Key changes: | ||||||
|  | 
 | ||||||
|  |   关键变化: | ||||||
|  | 
 | ||||||
|   - the validation attributes are gone (except `required`) because we'll be validating in code. |   - the validation attributes are gone (except `required`) because we'll be validating in code. | ||||||
| 
 | 
 | ||||||
|  |   - 验证属性没有了(除了`required`),因为我们将在代码中验证。 | ||||||
|  | 
 | ||||||
|   - `required` remains, not for validation purposes (we'll cover that in the code),  |   - `required` remains, not for validation purposes (we'll cover that in the code),  | ||||||
|   but rather for css styling and accessibility. |   but rather for css styling and accessibility. | ||||||
| 
 | 
 | ||||||
|  |   - 保留了`required`,不是为了验证目的(我们将在代码中再行解释),而是为了CSS样式和可访问性。 | ||||||
|  | 
 | ||||||
| .l-sub-section | .l-sub-section | ||||||
|   :marked |   :marked | ||||||
|     A future version of reactive forms will add the `required` HTML validation attribute to the DOM element |     A future version of reactive forms will add the `required` HTML validation attribute to the DOM element | ||||||
|     (and perhaps the `aria-required` attribute) when the control has the `required` validator function. |     (and perhaps the `aria-required` attribute) when the control has the `required` validator function. | ||||||
| 
 | 
 | ||||||
|  |     未来版本的响应式表单将会在控制器有`required`验证器函数时,添加`required` HTML验证属性到DOM元素(也可能添加`aria-required`属性)。  | ||||||
|  | 
 | ||||||
|     Until then, apply the `required` attribute _and_ add the `Validator.required` function |     Until then, apply the `required` attribute _and_ add the `Validator.required` function | ||||||
|     to the control model, as we'll do below. |     to the control model, as we'll do below. | ||||||
| 
 | 
 | ||||||
|  |     在此之前,添加`required`属性**以及**添加`Validator.required`函数到控制器模型,像我们下面这样做: | ||||||
|  | 
 | ||||||
| :marked | :marked | ||||||
|   - the `formControlName` replaces the `name` attribute; it serves the same |   - the `formControlName` replaces the `name` attribute; it serves the same | ||||||
|   purpose of correlating the input box with the Angular form control. |   purpose of correlating the input box with the Angular form control. | ||||||
| 
 | 
 | ||||||
|  |   - `formControlName`替换了`name`属性;它起到了关联输入框和Angular表单控制器的同样作用。 | ||||||
|  | 
 | ||||||
|   - the two-way `[(ngModel)]` binding is gone.  |   - the two-way `[(ngModel)]` binding is gone.  | ||||||
|   The reactive approach does not use data binding to move data into and out of the form controls. |   The reactive approach does not use data binding to move data into and out of the form controls. | ||||||
|   We do that in code. |   We do that in code. | ||||||
| 
 | 
 | ||||||
|  |   - 双向`[(ngModel)]`绑定消失了。 | ||||||
|  |   响应式表单方法不使用数据绑定从表单控制器移入和移出数据。我们在代码中做这些。 | ||||||
|  | 
 | ||||||
| .l-sub-section | .l-sub-section | ||||||
|   :marked |   :marked | ||||||
|     The retreat from data binding is a principle of the reactive paradigm rather than a technical limitation. |     The retreat from data binding is a principle of the reactive paradigm rather than a technical limitation. | ||||||
|  | 
 | ||||||
|  |     不适用表单数据绑定是响应式模式的原则,而非技术局限。 | ||||||
| :marked | :marked | ||||||
|   ### Component class |   ### Component class | ||||||
| 
 | 
 | ||||||
|  |   ### 组件类 | ||||||
|  | 
 | ||||||
|   The component class is now responsible for defining and managing the form control model. |   The component class is now responsible for defining and managing the form control model. | ||||||
| 
 | 
 | ||||||
|  |   组件类现在负责定义和管理表单控制器模型。  | ||||||
|  |    | ||||||
|   Angular no longer derives the control model from the template so we can no longer query for it. |   Angular no longer derives the control model from the template so we can no longer query for it. | ||||||
|   We create the Angular form control model explicitly with the help of the `FormBuilder`. |   We create the Angular form control model explicitly with the help of the `FormBuilder`. | ||||||
| 
 | 
 | ||||||
|  |   Angular不再从模板衍生控制器模型,所以我们不能再查询它。 | ||||||
|  |   我们利用`FormBuilder`来显式创建Angular表单控制器模型。 | ||||||
|  | 
 | ||||||
|   Here's the section of code devoted to that process, paired with the template-driven code it replaces: |   Here's the section of code devoted to that process, paired with the template-driven code it replaces: | ||||||
|  | 
 | ||||||
|  |   下面是负责该进程的代码部分,与被它取代的模板驱动代码相比: | ||||||
| +makeTabs( | +makeTabs( | ||||||
|   `cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts, |   `cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts, | ||||||
|    cb-form-validation/ts/app/template/hero-form-template2.component.ts`, |    cb-form-validation/ts/app/template/hero-form-template2.component.ts`, | ||||||
| @ -540,60 +571,114 @@ a#reactive | |||||||
| :marked | :marked | ||||||
|   - we inject the `FormBuilder` in a constructor. |   - we inject the `FormBuilder` in a constructor. | ||||||
| 
 | 
 | ||||||
|  |   - 我们注入`FormBuilder`到构造函数中。 | ||||||
|  | 
 | ||||||
|   - we call a `buildForm` method in the `ngOnInit` [lifecycle hook method](../guide/lifecycle-hooks.html#hooks-overview) |   - we call a `buildForm` method in the `ngOnInit` [lifecycle hook method](../guide/lifecycle-hooks.html#hooks-overview) | ||||||
|   because that's when we'll have the hero data. We'll call it again in the `addHero` method. |   because that's when we'll have the hero data. We'll call it again in the `addHero` method. | ||||||
|  | 
 | ||||||
|  |   - 我们在`ngOnInit`[生命周期钩子方法](../guide/lifecycle-hooks.html#hooks-overview)中调用`buildForm`方法, | ||||||
|  |   因为这正是我们拥有英雄数据的时刻。我们将在`addHero`方法中再次调用它。 | ||||||
|  | 
 | ||||||
| .l-sub-section | .l-sub-section | ||||||
|   :marked |   :marked | ||||||
|     A real app would retrieve the hero asynchronously from a data service, a task best performed in the `ngOnInit` hook. |     A real app would retrieve the hero asynchronously from a data service, a task best performed in the `ngOnInit` hook. | ||||||
|  | 
 | ||||||
|  |     真实的应用很可能从数据服务异步获取英雄,这个任务最好在`ngOnInit`生命周期钩子中进行。 | ||||||
| :marked | :marked | ||||||
|   - the `buildForm` method uses the `FormBuilder` (`fb`) to declare the form control model. |   - the `buildForm` method uses the `FormBuilder` (`fb`) to declare the form control model. | ||||||
|   Then it attaches the same `onValueChanged` handler (there's a one line difference)  |   Then it attaches the same `onValueChanged` handler (there's a one line difference)  | ||||||
|   to the form's `valueChanged` event and calls it immediately  |   to the form's `valueChanged` event and calls it immediately  | ||||||
|   to set error messages for the new control model. |   to set error messages for the new control model. | ||||||
| 
 | 
 | ||||||
|  |   - `buildForm`方法使用`FormBuilder`(`fb`)来声明表单控制器模型。 | ||||||
|  |   然后它将相同的`onValueChanged`(有一行代码不一样)处理器附加到表单的`valueChanged`事件, | ||||||
|  |   并立刻为新的控制器模型设置错误消息。 | ||||||
|  | 
 | ||||||
| :marked | :marked | ||||||
|   #### _FormBuilder_ declaration |   #### _FormBuilder_ declaration | ||||||
|  | 
 | ||||||
|  |   #### _FormBuilder_声明 | ||||||
|  |   | ||||||
|   The `FormBuilder` declaration object specifies the three controls of the sample's hero form. |   The `FormBuilder` declaration object specifies the three controls of the sample's hero form. | ||||||
| 
 | 
 | ||||||
|  |   `FormBuilder`声明对象指定了本例英雄表单的三个控制器。  | ||||||
|  | 
 | ||||||
|   Each control spec is a control name with an array value.  |   Each control spec is a control name with an array value.  | ||||||
|   The first array element is the current value of the corresponding hero field. |   The first array element is the current value of the corresponding hero field. | ||||||
|   The (optional) second value is a validator function or an array of validator functions. |   The (optional) second value is a validator function or an array of validator functions. | ||||||
| 
 | 
 | ||||||
|  |   每个控制器的设置都是控制器名字和数组值。 | ||||||
|  |   第一个数组元素是英雄控件对应的当前值。 | ||||||
|  |   第二个值(可选)是验证器函数或者验证器函数数组。 | ||||||
|  |    | ||||||
|   Most of the validator functions are stock validators provided by Angular as static methods of the `Validators` class. |   Most of the validator functions are stock validators provided by Angular as static methods of the `Validators` class. | ||||||
|   Angular has stock validators that correspond to the standard HTML validation attributes. |   Angular has stock validators that correspond to the standard HTML validation attributes. | ||||||
| 
 | 
 | ||||||
|  |   大多数验证器函数是Angular以`Validators`类的静态方法的形式提供的原装验证器。 | ||||||
|  |   Angular有一些原装验证器,与标准HTML验证属性一一对应。 | ||||||
|  | 
 | ||||||
|   The `forbiddenNames` validator on the `"name"` control is a custom validator,  |   The `forbiddenNames` validator on the `"name"` control is a custom validator,  | ||||||
|   discussed in a separate [section below](#custom-validation). |   discussed in a separate [section below](#custom-validation). | ||||||
| 
 | 
 | ||||||
|  |   `"name"`控制器上的`forbiddenNames`验证器是自定义验证器,在下面单独的[小结](#custom-validation)有所讨论。 | ||||||
|  | 
 | ||||||
| .l-sub-section   | .l-sub-section   | ||||||
|   :marked |   :marked | ||||||
|     Learn more about `FormBuilder` in a _forthcoming_ chapter on reactive forms.  |     Learn more about `FormBuilder` in a _forthcoming_ chapter on reactive forms.  | ||||||
| 
 | 
 | ||||||
|  |     到**即将到来**的响应式表单章,学习更多关于`FormBuilder`的知识。 | ||||||
| :marked | :marked | ||||||
|   #### Committing hero value changes |   #### Committing hero value changes | ||||||
| 
 | 
 | ||||||
|  |   #### 提交英雄值的更新 | ||||||
|  |    | ||||||
|   In two-way data binding, the user's changes flow automatically from the controls back to the data model properties. |   In two-way data binding, the user's changes flow automatically from the controls back to the data model properties. | ||||||
|   Reactive forms do not use data binding to update data model properties.  |   Reactive forms do not use data binding to update data model properties.  | ||||||
|   The developer decides _when and how_ to update the data model from control values. |   The developer decides _when and how_ to update the data model from control values. | ||||||
| 
 | 
 | ||||||
|  |   在双向数据绑定时,用户的修改自动从控制器流向数据模型属性。 | ||||||
|  |   响应式表单不适用数据绑定来更新数据模型属性。 | ||||||
|  |   开发者决定**何时**与**如何**从控制器的值更新数据模型。 | ||||||
|  | 
 | ||||||
|   This sample updates the model twice: |   This sample updates the model twice: | ||||||
|  | 
 | ||||||
|  |   本例更新模型两次: | ||||||
|  | 
 | ||||||
|   1. when the user submits the form |   1. when the user submits the form | ||||||
|  | 
 | ||||||
|  |   1. 当用户提交标单时 | ||||||
|  | 
 | ||||||
|   1. when the user chooses to add a new hero |   1. when the user chooses to add a new hero | ||||||
| 
 | 
 | ||||||
|  |   1. 当用户选择添加新英雄 | ||||||
|  | 
 | ||||||
|   The `onSubmit` method simply replaces the `hero` object with the combined values of the form: |   The `onSubmit` method simply replaces the `hero` object with the combined values of the form: | ||||||
|  | 
 | ||||||
|  |   `onSubmit`方法直接使用表单的值得合集来替换`hero`对象: | ||||||
|  | 
 | ||||||
| +makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts','on-submit')(format='.') | +makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts','on-submit')(format='.') | ||||||
| .l-sub-section | .l-sub-section | ||||||
|   :marked |   :marked | ||||||
|     This example is "lucky" in that the `heroForm.value` properties _just happen_ to |     This example is "lucky" in that the `heroForm.value` properties _just happen_ to | ||||||
|     correspond _exactly_ to the hero data object properties. |     correspond _exactly_ to the hero data object properties. | ||||||
|  | 
 | ||||||
|  |     本例非常“幸运”,因为`heroForm.value`属性**正好**与英雄数据对象属性对应。 | ||||||
| :marked | :marked | ||||||
|   The `addHero` method discards pending changes and creates a brand new `hero` model object. |   The `addHero` method discards pending changes and creates a brand new `hero` model object. | ||||||
|  | 
 | ||||||
|  |   `addHero`方法放弃未处理的变化,并创建一个崭新的`hero`模型对象。 | ||||||
|  | 
 | ||||||
| +makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts','add-hero')(format='.') | +makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts','add-hero')(format='.') | ||||||
| :marked | :marked | ||||||
|   Then it calls `buildForm` again which replaces the previous `heroForm` control model with a new one. |   Then it calls `buildForm` again which replaces the previous `heroForm` control model with a new one. | ||||||
|   The `<form>` tag's `[formGroup]` binding refreshes the page with the new control model. |   The `<form>` tag's `[formGroup]` binding refreshes the page with the new control model. | ||||||
| 
 | 
 | ||||||
|  |   然后它再次调用`buildForm`,用一个新对象替换了之前的`heroForm`控制器模型。 | ||||||
|  |   `<form>`标签的`[formGroup]`绑定使用这个新的控制器模型更新页面。 | ||||||
|  | 
 | ||||||
|   Here's the complete reactive component file, compared to the two template-driven component files. |   Here's the complete reactive component file, compared to the two template-driven component files. | ||||||
|  | 
 | ||||||
|  |   下面是完整的响应式表单的组件文件,与两个模板驱动组件文件对比: | ||||||
| +makeTabs( | +makeTabs( | ||||||
|   `cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts, |   `cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts, | ||||||
|    cb-form-validation/ts/app/template/hero-form-template2.component.ts,  |    cb-form-validation/ts/app/template/hero-form-template2.component.ts,  | ||||||
| @ -608,74 +693,130 @@ a#reactive | |||||||
|     Run the [live example](#live-example) to see how the reactive form behaves |     Run the [live example](#live-example) to see how the reactive form behaves | ||||||
|     and to compare all of the files in this cookbook sample. |     and to compare all of the files in this cookbook sample. | ||||||
| 
 | 
 | ||||||
|  |     运行[在线例子](#live-example),查看响应式表单是的行为,并与本章中的例子文件作比较。 | ||||||
|  | 
 | ||||||
| .l-main-section | .l-main-section | ||||||
| a#custom-validation | a#custom-validation | ||||||
| :marked | :marked | ||||||
|   ## Custom validation |   ## Custom validation | ||||||
|  | 
 | ||||||
|  |   ## 自定义验证 | ||||||
|  | 
 | ||||||
|   This cookbook sample has a custom `forbiddenNamevalidator` function that's applied to both the  |   This cookbook sample has a custom `forbiddenNamevalidator` function that's applied to both the  | ||||||
|   template-driven and the reactive form controls. It's in the `app/shared` folder |   template-driven and the reactive form controls. It's in the `app/shared` folder | ||||||
|   and declared in the `SharedModule`. |   and declared in the `SharedModule`. | ||||||
| 
 | 
 | ||||||
|  |   本烹饪书例子有一个自定义`forbiddenNameValidator`函数,在模板驱动和响应式表单中都有使用。 | ||||||
|  |   它在`app/shared`目录,在`SharedModule`中被声明。 | ||||||
|  | 
 | ||||||
|   Here's the `forbiddenNamevalidator` function itself: |   Here's the `forbiddenNamevalidator` function itself: | ||||||
|  | 
 | ||||||
|  |   下面是`forbiddenNameValidator`函数: | ||||||
|  | 
 | ||||||
| +makeExample('cb-form-validation/ts/app/shared/forbidden-name.directive.ts','custom-validator', 'shared/forbidden-name.directive.ts (forbiddenNameValidator)')(format='.') | +makeExample('cb-form-validation/ts/app/shared/forbidden-name.directive.ts','custom-validator', 'shared/forbidden-name.directive.ts (forbiddenNameValidator)')(format='.') | ||||||
| :marked | :marked | ||||||
|   The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name |   The function is actually a factory that takes a regular expression to detect a _specific_ forbidden name | ||||||
|   and returns a validator function. |   and returns a validator function. | ||||||
| 
 | 
 | ||||||
|  |   该函数其实是一个工厂函数,接受一个正则表达式,用来检测**指定**的禁止的名字,并返回验证器函数。 | ||||||
|  | 
 | ||||||
|   In this sample, the forbidden name is "bob";  |   In this sample, the forbidden name is "bob";  | ||||||
|   the validator rejects any hero name containing "bob". |   the validator rejects any hero name containing "bob". | ||||||
|   Elsewhere it could reject "alice" or any name that the configuring regular expression matches. |   Elsewhere it could reject "alice" or any name that the configuring regular expression matches. | ||||||
| 
 | 
 | ||||||
|  |   在本例中,禁止的名字是"bob"; | ||||||
|  |   验证器拒绝任何带有"bob"的英雄名字。 | ||||||
|  |   在其他地方,只要配置的正则表达式可以匹配上,它可能拒绝"alice"或者任何其他名字。 | ||||||
|  |    | ||||||
|   The `forbiddenNamevalidator` factory returns the configured validator function. |   The `forbiddenNamevalidator` factory returns the configured validator function. | ||||||
|   That function takes an Angular control object and returns _either_ |   That function takes an Angular control object and returns _either_ | ||||||
|   null if the control value is valid _or_ a validation error object. |   null if the control value is valid _or_ a validation error object. | ||||||
|   The validation error object typically has a property whose name is the validation key ('forbiddenName') |   The validation error object typically has a property whose name is the validation key ('forbiddenName') | ||||||
|   and whose value is an arbitrary dictionary of values that we could insert into an error message (`{name}`). |   and whose value is an arbitrary dictionary of values that we could insert into an error message (`{name}`). | ||||||
| 
 | 
 | ||||||
|  |   `forbiddenNameValidator`工厂函数返回配置好的验证器函数。 | ||||||
|  |   该函数接受一个Angular控制器对象,并在控制器值有效时返回null,或无效时返回验证错误对象。 | ||||||
|  |   验证错误对象通常有一个名为验证秘钥(`forbiddenName`)的属性。其值为一个任意词典,我们可以用来插入错误信息(`{name}`)。 | ||||||
|  | 
 | ||||||
| .l-sub-section | .l-sub-section | ||||||
|   :marked |   :marked | ||||||
|     Learn more about validator functions in a _forthcoming_ chapter on custom form validation. |     Learn more about validator functions in a _forthcoming_ chapter on custom form validation. | ||||||
|  | 
 | ||||||
|  |     在**即将到来**的自定义表单验证章节,学习更多关于验证器函数的知识。 | ||||||
| :marked | :marked | ||||||
|   #### Custom validation directive |   #### Custom validation directive | ||||||
|  | 
 | ||||||
|  |   #### 自定义验证指令 | ||||||
|  | 
 | ||||||
|   In the reactive forms component we added a configured `forbiddenNamevalidator` |   In the reactive forms component we added a configured `forbiddenNamevalidator` | ||||||
|   to the bottom of the `'name'` control's validator function list. |   to the bottom of the `'name'` control's validator function list. | ||||||
|  | 
 | ||||||
|  |   在响应式表单组件中,我们在`'name'`控制器的验证函数列表的底部添加了一个配置了的`forbiddenNameValidator`。 | ||||||
|  | 
 | ||||||
| +makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts','name-validators', 'reactive/hero-form-reactive.component.ts (name validators)')(format='.') | +makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts','name-validators', 'reactive/hero-form-reactive.component.ts (name validators)')(format='.') | ||||||
| :marked | :marked | ||||||
|   In the template-driven component template, we add the selector (`forbiddenName`) of a custom _attribute directive_ to the name's input box |   In the template-driven component template, we add the selector (`forbiddenName`) of a custom _attribute directive_ to the name's input box | ||||||
|   and configured it to reject "bob". |   and configured it to reject "bob". | ||||||
|  | 
 | ||||||
|  |   在模板驱动组件的模板中,我们在name的输入框元素中添加了自定义**属性指令**的选择器(`forbiddenName`),并配置它来拒绝“bob”。 | ||||||
|  | 
 | ||||||
| +makeExample('cb-form-validation/ts/app/template/hero-form-template2.component.html','name-input', 'template/hero-form-template2.component.html (name input)')(format='.') | +makeExample('cb-form-validation/ts/app/template/hero-form-template2.component.html','name-input', 'template/hero-form-template2.component.html (name input)')(format='.') | ||||||
| :marked | :marked | ||||||
|   The corresponding `ForbiddenValidatorDirective` is a wrapper around the `forbiddenNamevalidator`. |   The corresponding `ForbiddenValidatorDirective` is a wrapper around the `forbiddenNamevalidator`. | ||||||
| 
 | 
 | ||||||
|  |   对应的`ForbiddenValidatorDirective`包装了`forbiddenNamevalidator`。 | ||||||
|  |    | ||||||
|   Angular forms recognizes the directive's role in the validation process because the directive registers itself |   Angular forms recognizes the directive's role in the validation process because the directive registers itself | ||||||
|   with the `NG_VALIDATORS` provider, a provider with an extensible collection of validation directives. |   with the `NG_VALIDATORS` provider, a provider with an extensible collection of validation directives. | ||||||
|  | 
 | ||||||
|  |   Angular表单接受指令在验证流程中的作用,因为指令注册自己到`NG_VALIDATORS`提供商中,该提供商拥有可扩展的验证指令集。 | ||||||
|  | 
 | ||||||
| +makeExample('cb-form-validation/ts/app/shared/forbidden-name.directive.ts','directive-providers', 'shared/forbidden-name.directive.ts (providers)')(format='.') | +makeExample('cb-form-validation/ts/app/shared/forbidden-name.directive.ts','directive-providers', 'shared/forbidden-name.directive.ts (providers)')(format='.') | ||||||
| :marked | :marked | ||||||
|   The rest of the directive is unremarkable and we present it here without further comment. |   The rest of the directive is unremarkable and we present it here without further comment. | ||||||
|  | 
 | ||||||
|  |   指令的剩余部分没有什么特殊的,所以我们将它展示在下面,不作任何注解。 | ||||||
|  | 
 | ||||||
| +makeExample('cb-form-validation/ts/app/shared/forbidden-name.directive.ts','directive', 'shared/forbidden-name.directive.ts (directive)') | +makeExample('cb-form-validation/ts/app/shared/forbidden-name.directive.ts','directive', 'shared/forbidden-name.directive.ts (directive)') | ||||||
| :marked | :marked | ||||||
| .l-sub-section | .l-sub-section | ||||||
|   :marked |   :marked | ||||||
|     See the [Attribute Directives](../guide/attribute-directives.html) chapter. |     See the [Attribute Directives](../guide/attribute-directives.html) chapter. | ||||||
| 
 | 
 | ||||||
|  |     参见[属性型指令](../guide/attribute-directives.html)章节。 | ||||||
|  | 
 | ||||||
| .l-main-section | .l-main-section | ||||||
| a#testing | a#testing | ||||||
| :marked | :marked | ||||||
|   ## Testing Considerations |   ## Testing Considerations | ||||||
| 
 | 
 | ||||||
|  |   ## 测试注意事项 | ||||||
|  | 
 | ||||||
|   We can write _isolated unit tests_ of validation and control logic in _Reactive Forms_. |   We can write _isolated unit tests_ of validation and control logic in _Reactive Forms_. | ||||||
| 
 | 
 | ||||||
|  |   我们可以为**响应式表单**的验证器和控制器逻辑编写**孤立单元测试**。 | ||||||
|  | 
 | ||||||
|   _Isolated unit tests_ probe the component class directly, independent of its |   _Isolated unit tests_ probe the component class directly, independent of its | ||||||
|   interactions with its template, the DOM, other dependencies, or Angular itself. |   interactions with its template, the DOM, other dependencies, or Angular itself. | ||||||
| 
 | 
 | ||||||
|  |   **孤立单元测试**直接检测组件类,与组件和它的模板的交互、DOM、其他以来和Angular本省都无关。 | ||||||
|  | 
 | ||||||
|   Such tests have minimal setup, are quick to write, and easy to maintain. |   Such tests have minimal setup, are quick to write, and easy to maintain. | ||||||
|   They do not require the `Angular TestBed` or asynchronous testing practices. |   They do not require the `Angular TestBed` or asynchronous testing practices. | ||||||
| 
 | 
 | ||||||
|  |   这样的测试具有简单设置#,快速编写和容易维护的特征。它们不需要`Angular TestBed`或异步测试工序。 | ||||||
|  | 
 | ||||||
|   That's not possible with _Template-driven_ forms. |   That's not possible with _Template-driven_ forms. | ||||||
|   The template-driven approach relies on Angular to produce the control model and  |   The template-driven approach relies on Angular to produce the control model and  | ||||||
|   to derive validation rules from the HTML validation attributes. |   to derive validation rules from the HTML validation attributes. | ||||||
|   You must use the `Angular TestBed` to create component test instances, |   You must use the `Angular TestBed` to create component test instances, | ||||||
|   write asynchronous tests, and interact with the DOM. |   write asynchronous tests, and interact with the DOM. | ||||||
| 
 | 
 | ||||||
|  |   这对**模板驱动**表单来说是不可能的。 | ||||||
|  |   模板驱动方法依靠Angular来生成控制器模型并从HTML验证属性中衍生验证规则。 | ||||||
|  |   你必须使用`Angular TestBed`来创建组件测试实例,编写异步测试并与DOM交互。 | ||||||
|  | 
 | ||||||
|   While not difficult, this takes more time, work and skill —  |   While not difficult, this takes more time, work and skill —  | ||||||
|   factors that tend to diminish test code coverage and quality. |   factors that tend to diminish test code coverage and quality. | ||||||
|  | 
 | ||||||
|  |   虽然这种测试并不困难,但是它需要更多时间、工作和能力 - 这些因素往往会降低测试代码覆盖率和测试质量。 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user