docs(aio): incorporate Ward's comments
This commit is contained in:
parent
fb877696bf
commit
2b1de07f02
|
@ -1,12 +1,12 @@
|
||||||
# Form Validation
|
# Form Validation
|
||||||
|
|
||||||
{@a top}
|
|
||||||
|
|
||||||
|
|
||||||
Improve overall data quality by validating user input for accuracy and completeness.
|
Improve overall data quality by validating user input for accuracy and completeness.
|
||||||
|
|
||||||
This page shows how to validate user input in the UI and display useful validation messages
|
This page shows how to validate user input in the UI and display useful validation messages
|
||||||
using first the template driven forms and then the reactive forms approach.
|
using first the Template Driven Forms and then the Reactive Forms approach.
|
||||||
|
|
||||||
<div class="l-sub-section">
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
@ -34,23 +34,23 @@ Angular forms include a number of built-in validator functions, which are functi
|
||||||
that help you check common user input in forms. In addition to the built-in
|
that help you check common user input in forms. In addition to the built-in
|
||||||
validators covered here of `minlength`, `maxlength`,
|
validators covered here of `minlength`, `maxlength`,
|
||||||
and `required`, there are others such as `min`, `max`, `email` and `pattern`
|
and `required`, there are others such as `min`, `max`, `email` and `pattern`
|
||||||
for template driven as well as reactive forms.
|
for Template Driven as well as Reactive Forms.
|
||||||
For a full list of built-in validators,
|
For a full list of built-in validators,
|
||||||
see the [Validators](api/forms/Validators) API reference.
|
see the [Validators](api/forms/Validators) API reference.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a template1}
|
|
||||||
|
|
||||||
|
|
||||||
## Simple template driven forms
|
|
||||||
|
|
||||||
In the template driven approach, you arrange
|
## Simple Template Driven Forms
|
||||||
|
|
||||||
|
In the Template Driven approach, you arrange
|
||||||
[form elements](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms_in_HTML) in the component's template.
|
[form elements](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/Forms_in_HTML) in the component's template.
|
||||||
|
|
||||||
You add Angular form directives (mostly directives beginning `ng...`) to help
|
You add Angular form directives (mostly directives beginning `ng...`) to help
|
||||||
Angular construct a corresponding internal control model that implements form functionality.
|
Angular construct a corresponding internal control model that implements form functionality.
|
||||||
In template driven forms, the control model is _implicit_ in the template.
|
In Template Driven forms, the control model is _implicit_ in the template.
|
||||||
|
|
||||||
To validate user input, you add [HTML validation attributes](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)
|
To validate user input, you add [HTML validation attributes](https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation)
|
||||||
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.
|
||||||
|
@ -119,9 +119,9 @@ as well as other code to support the view.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Use this template driven validation technique when working with static forms with simple, standard validation rules.
|
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:
|
Here are the complete files for the first version of `HeroFormTemplateCompononent` in the Template Driven approach:
|
||||||
|
|
||||||
|
|
||||||
<code-tabs>
|
<code-tabs>
|
||||||
|
@ -139,10 +139,8 @@ Here are the complete files for the first version of `HeroFormTemplateCompononen
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a template2}
|
|
||||||
|
|
||||||
|
## Template Driven Forms with validation messages in code
|
||||||
## Template driven forms with validation messages in code
|
|
||||||
|
|
||||||
While the layout is straightforward,
|
While the layout is straightforward,
|
||||||
there are obvious shortcomings with the way it's handling validation messages:
|
there are obvious shortcomings with the way it's handling validation messages:
|
||||||
|
@ -159,7 +157,7 @@ In this example, you can move the logic and the messages into the component with
|
||||||
the template and component.
|
the template and component.
|
||||||
|
|
||||||
Here's the hero name again, excerpted from the revised template
|
Here's the hero name again, excerpted from the revised template
|
||||||
(Template 2), next to the original version:
|
(template 2), next to the original version:
|
||||||
|
|
||||||
<code-tabs>
|
<code-tabs>
|
||||||
|
|
||||||
|
@ -293,14 +291,14 @@ In short, there are more opportunities to improve message handling now that text
|
||||||
{@a formmodule}
|
{@a formmodule}
|
||||||
|
|
||||||
|
|
||||||
### _FormModule_ and template driven forms
|
### _FormModule_ and Template Driven forms
|
||||||
|
|
||||||
Angular has two different forms modules—`FormsModule` and
|
Angular has two different forms modules—`FormsModule` and
|
||||||
`ReactiveFormsModule`—that correspond with the
|
`ReactiveFormsModule`—that correspond with the
|
||||||
two approaches to form development. Both modules come
|
two approaches to form development. Both modules come
|
||||||
from the same `@angular/forms` library package.
|
from the same `@angular/forms` library package.
|
||||||
|
|
||||||
You've been reviewing the template driven approach which requires the `FormsModule`.
|
You've been reviewing the Template Driven approach which requires the `FormsModule`.
|
||||||
Here's how you imported it in the `HeroFormTemplateModule`.
|
Here's how you imported it in the `HeroFormTemplateModule`.
|
||||||
|
|
||||||
|
|
||||||
|
@ -328,13 +326,13 @@ They're not germane to the validation story. Look at the [live example](guide/fo
|
||||||
{@a reactive}
|
{@a reactive}
|
||||||
|
|
||||||
|
|
||||||
## Reactive forms with validation in code
|
## Reactive Forms with validation in code
|
||||||
|
|
||||||
In the template driven approach, you mark up the template with form elements, validation attributes,
|
In the Template Driven approach, you mark up the template with form elements, validation attributes,
|
||||||
and `ng...` directives from the Angular `FormsModule`.
|
and `ng...` directives from the Angular `FormsModule`.
|
||||||
At runtime, Angular interprets the template and derives its _form control model_.
|
At runtime, Angular interprets the template and derives its _form control model_.
|
||||||
|
|
||||||
**Reactive Forms** take a different approach.
|
**Reactive Forms** takes a different approach.
|
||||||
You create the form control model in code. You write the template with form elements
|
You create the form control model in code. You write the template with form elements
|
||||||
and `form...` directives from the Angular `ReactiveFormsModule`.
|
and `form...` directives from the Angular `ReactiveFormsModule`.
|
||||||
At runtime, Angular binds the template elements to your control model based on your instructions.
|
At runtime, Angular binds the template elements to your control model based on your instructions.
|
||||||
|
@ -345,15 +343,15 @@ This allows you to do the following:
|
||||||
* Manipulate the control model dynamically from within the component.
|
* Manipulate the control model dynamically from within the component.
|
||||||
* [Test](guide/form-validation#testing) validation and control logic with isolated unit tests.
|
* [Test](guide/form-validation#testing) validation and control logic with isolated unit tests.
|
||||||
|
|
||||||
The following sample re-writes the hero form in _reactive forms_ style.
|
The following sample re-writes the hero form in Reactive Forms style.
|
||||||
|
|
||||||
|
|
||||||
{@a reactive-forms-module}
|
{@a reactive-forms-module}
|
||||||
|
|
||||||
|
|
||||||
### Switch to the _ReactiveFormsModule_
|
### Switch to the _ReactiveFormsModule_
|
||||||
The reactive forms classes and directives come from the Angular `ReactiveFormsModule`, not the `FormsModule`.
|
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:
|
The application module for the Reactive Forms feature in this sample looks like this:
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.module.ts" title="src/app/reactive/hero-form-reactive.module.ts" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.module.ts" title="src/app/reactive/hero-form-reactive.module.ts" linenums="false">
|
||||||
|
|
||||||
|
@ -361,7 +359,7 @@ The application module for the reactive forms feature in this sample looks like
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
The reactive forms feature module and component are in the `src/app/reactive` folder.
|
The Reactive Forms feature module and component are in the `src/app/reactive` folder.
|
||||||
Focus on the `HeroFormReactiveComponent` there, starting with its template.
|
Focus on the `HeroFormReactiveComponent` there, starting with its template.
|
||||||
|
|
||||||
|
|
||||||
|
@ -381,8 +379,8 @@ The `heroForm` is the control model that the component class builds and maintain
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Next, modify the template HTML elements to match the _reactive forms_ style.
|
Next, 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:
|
||||||
|
|
||||||
<code-tabs>
|
<code-tabs>
|
||||||
|
|
||||||
|
@ -405,19 +403,17 @@ validating happens in code.
|
||||||
* `required` remains, not for validation purposes (that's in the code),
|
* `required` remains, not for validation purposes (that's in the code),
|
||||||
but rather for css styling and accessibility.
|
but rather for css styling and accessibility.
|
||||||
|
|
||||||
<!--
|
|
||||||
<div class="l-sub-section">
|
<div class="l-sub-section">
|
||||||
|
|
||||||
|
Currently, Reactive Forms doesn't add the `required` or `aria-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
|
when the control has the `required` validator function.
|
||||||
(and perhaps the `aria-required` attribute) when the control has the `required` validator function.
|
|
||||||
|
|
||||||
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 you'll see below.
|
to the control model, as you'll see below.
|
||||||
|
|
||||||
|
</div>
|
||||||
</div>-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -429,13 +425,6 @@ The reactive approach does not use data binding to move data into and out of the
|
||||||
That's all in code.
|
That's all in code.
|
||||||
|
|
||||||
|
|
||||||
<!--<div class="l-sub-section">
|
|
||||||
|
|
||||||
The retreat from data binding is a principle of the reactive paradigm rather than a technical limitation.
|
|
||||||
|
|
||||||
</div>-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a reactive-component-class}
|
{@a reactive-component-class}
|
||||||
|
|
||||||
|
@ -448,7 +437,7 @@ Angular no longer derives the control model from the template so you can no long
|
||||||
You can create the Angular form control model explicitly with
|
You can create the Angular form control model explicitly with
|
||||||
the help of the `FormBuilder` class.
|
the help of the `FormBuilder` class.
|
||||||
|
|
||||||
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:
|
||||||
|
|
||||||
<code-tabs>
|
<code-tabs>
|
||||||
|
|
||||||
|
@ -508,18 +497,17 @@ discussed in a separate [section below](guide/form-validation#custom-validation)
|
||||||
|
|
||||||
Learn more about `FormBuilder` in the [Introduction to FormBuilder](guide/reactive-forms#formbuilder) section of Reactive Forms guide.
|
Learn more about `FormBuilder` in the [Introduction to FormBuilder](guide/reactive-forms#formbuilder) section of Reactive Forms guide.
|
||||||
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
{@a committing-changes}
|
{@a committing-changes}
|
||||||
|
|
||||||
|
|
||||||
#### 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.
|
A Reactive Forms component should not use data binding to
|
||||||
|
automatically 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:
|
||||||
|
@ -534,18 +522,6 @@ The `onSubmit()` method simply replaces the `hero` object with the combined valu
|
||||||
</code-example>
|
</code-example>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!--<div class="l-sub-section">
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
This example is lucky in that the `heroForm.value` properties _just happen_ to
|
|
||||||
correspond _exactly_ to the hero data object properties.
|
|
||||||
|
|
||||||
</div>
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="add-hero" title="form-validation/src/app/reactive/hero-form-reactive.component.ts" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="add-hero" title="form-validation/src/app/reactive/hero-form-reactive.component.ts" linenums="false">
|
||||||
|
@ -557,7 +533,7 @@ The `addHero()` method discards pending changes and creates a brand new `hero` m
|
||||||
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.
|
||||||
|
|
||||||
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.
|
||||||
|
|
||||||
<code-tabs>
|
<code-tabs>
|
||||||
|
|
||||||
|
@ -595,7 +571,7 @@ and to compare all of the files in this sample.
|
||||||
|
|
||||||
## 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 `src/app/shared` folder
|
Template Driven and the reactive form controls. It's in the `src/app/shared` folder
|
||||||
and declared in the `SharedModule`.
|
and declared in the `SharedModule`.
|
||||||
|
|
||||||
Here's the `forbiddenNameValidator()` function:
|
Here's the `forbiddenNameValidator()` function:
|
||||||
|
@ -624,7 +600,7 @@ and whose value is an arbitrary dictionary of values that you could insert into
|
||||||
|
|
||||||
|
|
||||||
### Custom validation directive
|
### Custom validation directive
|
||||||
In the reactive forms component, the `'name'` control's validator function list
|
In the Reactive Forms component, the `'name'` control's validator function list
|
||||||
has a `forbiddenNameValidator` at the bottom.
|
has a `forbiddenNameValidator` at the bottom.
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="name-validators" title="reactive/hero-form-reactive.component.ts (name validators)" linenums="false">
|
<code-example path="form-validation/src/app/reactive/hero-form-reactive.component.ts" region="name-validators" title="reactive/hero-form-reactive.component.ts (name validators)" linenums="false">
|
||||||
|
@ -633,7 +609,7 @@ has a `forbiddenNameValidator` at the bottom.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
In the _template driven_ example, the `<input>` has the selector (`forbiddenName`)
|
In the Template Driven example, the `<input>` has the selector (`forbiddenName`)
|
||||||
of a custom _attribute directive_, which rejects "bob".
|
of a custom _attribute directive_, which rejects "bob".
|
||||||
|
|
||||||
<code-example path="form-validation/src/app/template/hero-form-template2.component.html" region="name-input" title="template/hero-form-template2.component.html (name input)" linenums="false">
|
<code-example path="form-validation/src/app/template/hero-form-template2.component.html" region="name-input" title="template/hero-form-template2.component.html (name input)" linenums="false">
|
||||||
|
@ -704,7 +680,7 @@ see [Attribute Directives](guide/attribute-directives).
|
||||||
|
|
||||||
## Testing Considerations
|
## Testing Considerations
|
||||||
|
|
||||||
You can write _isolated unit tests_ of validation and control logic in _Reactive Forms_.
|
You 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.
|
||||||
|
@ -712,8 +688,8 @@ interactions with its template, the DOM, other dependencies, or Angular itself.
|
||||||
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.
|
||||||
|
|
||||||
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.
|
||||||
|
|
Loading…
Reference in New Issue