angular-cn/aio/dist/generated/docs/guide/form-validation.json

5 lines
39 KiB
JSON
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{
"id": "guide/form-validation",
"title": "Validating form input",
"contents": "\n\n\n<div class=\"github-links\">\n <a href=\"https://github.com/angular/angular/edit/master/aio/content/guide/form-validation.md?message=docs%3A%20describe%20your%20change...\" aria-label=\"Suggest Edits\" title=\"Suggest Edits\"><i class=\"material-icons\" aria-hidden=\"true\" role=\"img\">mode_edit</i></a>\n</div>\n\n\n<div class=\"content\">\n <h1 id=\"validating-form-input\">Validating form input<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#validating-form-input\"><i class=\"material-icons\">link</i></a></h1>\n<p>You can improve overall data quality by validating user input for accuracy and completeness.\nThis page shows how to validate user input from the UI and display useful validation messages,\nin both reactive and template-driven forms.</p>\n<p><strong>Prerequisites</strong></p>\n<p>Before reading about form validation, you should have a basic understanding of the following.</p>\n<ul>\n<li>\n<p><a href=\"https://www.typescriptlang.org/\" title=\"The TypeScript language\">TypeScript</a> and HTML5 programming.</p>\n</li>\n<li>\n<p>Fundamental concepts of <a href=\"guide/architecture\" title=\"Introduction to Angular app-design concepts\">Angular app design</a>.</p>\n</li>\n<li>\n<p>The <a href=\"guide/forms-overview\" title=\"Introduction to Angular forms\">two types of forms that Angular supports</a>.</p>\n</li>\n<li>\n<p>Basics of either <a href=\"guide/forms\" title=\"Template-driven forms guide\">Template-driven Forms</a> or <a href=\"guide/reactive-forms\" title=\"Reactive forms guide\">Reactive Forms</a>.</p>\n</li>\n</ul>\n<div class=\"alert is-helpful\">\n<p>Get the complete example code for the reactive and template-driven forms used here to illustrate form validation.\nRun the <live-example></live-example>.</p>\n</div>\n<a id=\"template-driven-validation\"></a>\n<h2 id=\"validating-input-in-template-driven-forms\">Validating input in template-driven forms<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#validating-input-in-template-driven-forms\"><i class=\"material-icons\">link</i></a></h2>\n<p>To add validation to a template-driven form, you add the same validation attributes as you\nwould with <a href=\"https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation\">native HTML form validation</a>.\nAngular uses directives to match these attributes with validator functions in the framework.</p>\n<p>Every time the value of a form control changes, Angular runs validation and generates\neither a list of validation errors that results in an INVALID status, or null, which results in a VALID status.</p>\n<p>You can then inspect the control's state by exporting <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a></code> to a local template variable.\nThe following example exports <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">NgModel</a></code> into a variable called <code>name</code>:</p>\n<code-example path=\"form-validation/src/app/template/hero-form-template.component.html\" region=\"name-with-error-msg\" header=\"template/hero-form-template.component.html (name)\">\n&#x3C;input id=\"name\" name=\"name\" class=\"form-control\"\n required <a href=\"api/forms/MinLengthValidator\" class=\"code-anchor\">minlength</a>=\"4\" appForbiddenName=\"bob\"\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"hero.name\" #name=\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\" >\n\n&#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"name.invalid &#x26;&#x26; (name.dirty || name.touched)\"\n class=\"alert alert-danger\">\n\n &#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"name.errors.required\">\n Name is required.\n &#x3C;/div>\n &#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"name.errors.minlength\">\n Name must be at least 4 characters long.\n &#x3C;/div>\n &#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"name.errors.forbiddenName\">\n Name cannot be Bob.\n &#x3C;/div>\n\n&#x3C;/div>\n\n</code-example>\n<p>Notice the following features illustrated by the example.</p>\n<ul>\n<li>\n<p>The <code>&#x3C;input></code> element carries the HTML validation attributes: <code>required</code> and <code><a href=\"api/forms/MinLengthValidator\" class=\"code-anchor\">minlength</a></code>. It\nalso carries a custom validator directive, <code>forbiddenName</code>. For more\ninformation, see the <a href=\"guide/form-validation#custom-validators\">Custom validators</a> section.</p>\n</li>\n<li>\n<p><code>#name=\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\"</code> exports <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">NgModel</a></code> into a local variable called <code>name</code>. <code><a href=\"api/forms/NgModel\" class=\"code-anchor\">NgModel</a></code> mirrors many of the properties of its underlying\n<code><a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a></code> instance, so you can use this in the template to check for control states such as <code>valid</code> and <code>dirty</code>. For a full list of control properties, see the <a href=\"api/forms/AbstractControl\">AbstractControl</a>\nAPI reference.</p>\n<ul>\n<li>\n<p>The <code>*<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a></code> on the <code>&#x3C;div></code> element reveals a set of nested message <code>divs</code>\nbut only if the <code>name</code> is invalid and the control is either <code>dirty</code> or <code>touched</code>.</p>\n</li>\n<li>\n<p>Each nested <code>&#x3C;div></code> can present a custom message for one of the possible validation errors.\nThere are messages for <code>required</code>, <code><a href=\"api/forms/MinLengthValidator\" class=\"code-anchor\">minlength</a></code>, and <code>forbiddenName</code>.</p>\n</li>\n</ul>\n</li>\n</ul>\n<a id=\"dirty-or-touched\"></a>\n<div class=\"alert is-helpful\">\n<p>To prevent the validator from displaying errors before the user has a chance to edit the form, you should check for either the <code>dirty</code> or <code>touched</code> states in a control.</p>\n<ul>\n<li>When the user changes the value in the watched field, the control is marked as \"dirty\".</li>\n<li>When the user blurs the form control element, the control is marked as \"touched\".</li>\n</ul>\n</div>\n<a id=\"reactive-form-validation\"></a>\n<h2 id=\"validating-input-in-reactive-forms\">Validating input in reactive forms<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#validating-input-in-reactive-forms\"><i class=\"material-icons\">link</i></a></h2>\n<p>In a reactive form, the source of truth is the component class.\nInstead of adding validators through attributes in the template, you add validator functions directly to the form control model in the component class.\nAngular then calls these functions whenever the value of the control changes.</p>\n<h3 id=\"validator-functions\">Validator functions<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#validator-functions\"><i class=\"material-icons\">link</i></a></h3>\n<p>Validator functions can be either synchronous or asynchronous.</p>\n<ul>\n<li>\n<p><strong>Sync validators</strong>: Synchronous functions that take a control instance and immediately return either a set of validation errors or <code>null</code>. You can pass these in as the second argument when you instantiate a <code><a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a></code>.</p>\n</li>\n<li>\n<p><strong>Async validators</strong>: Asynchronous functions that take a control instance and return a Promise\nor Observable that later emits a set of validation errors or <code>null</code>. You can\npass these in as the third argument when you instantiate a <code><a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a></code>.</p>\n</li>\n</ul>\n<p>For performance reasons, Angular only runs async validators if all sync validators pass. Each must complete before errors are set.</p>\n<h3 id=\"built-in-validator-functions\">Built-in validator functions<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#built-in-validator-functions\"><i class=\"material-icons\">link</i></a></h3>\n<p>You can choose to <a href=\"guide/form-validation#custom-validators\">write your own validator functions</a>, or you can use some of Angular's built-in validators.</p>\n<p>The same built-in validators that are available as attributes in template-driven forms, such as <code>required</code> and <code><a href=\"api/forms/MinLengthValidator\" class=\"code-anchor\">minlength</a></code>, are all available to use as functions from the <code><a href=\"api/forms/Validators\" class=\"code-anchor\">Validators</a></code> class.\nFor a full list of built-in validators, see the <a href=\"api/forms/Validators\">Validators</a> API reference.</p>\n<p>To update the hero form to be a reactive form, you can use some of the same\nbuilt-in validators—this time, in function form, as in the following example.</p>\n<a id=\"reactive-component-class\"></a>\n<code-example path=\"form-validation/src/app/reactive/hero-form-reactive.component.1.ts\" region=\"form-group\" header=\"reactive/hero-form-reactive.component.ts (validator functions)\">\nngOnInit(): void {\n this.heroForm = new <a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a>({\n name: new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(this.hero.name, [\n Validators.required,\n Validators.minLength(4),\n forbiddenNameValidator(/bob/i) // &#x3C;-- Here's how you pass in the custom validator.\n ]),\n alterEgo: new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(this.hero.alterEgo),\n power: new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(this.hero.power, Validators.required)\n });\n\n}\n\nget name() { return this.heroForm.get('name'); }\n\nget power() { return this.heroForm.get('power'); }\n\n</code-example>\n<p>In this example, the <code>name</code> control sets up two built-in validators—<code>Validators.required</code> and <code>Validators.minLength(4)</code>—and one custom validator, <code>forbiddenNameValidator</code>. (For more details see <a href=\"guide/form-validation#custom-validators\">custom validators</a> below.)</p>\n<p>All of these validators are synchronous, so they are passed as the second argument. Notice that you can support multiple validators by passing the functions in as an array.</p>\n<p>This example also adds a few getter methods. In a reactive form, you can always access any form control through the <code>get</code> method on its parent group, but sometimes it's useful to define getters as shorthand for the template.</p>\n<p>If you look at the template for the <code>name</code> input again, it is fairly similar to the template-driven example.</p>\n<code-example path=\"form-validation/src/app/reactive/hero-form-reactive.component.html\" region=\"name-with-error-msg\" header=\"reactive/hero-form-reactive.component.html (name with error msg)\">\n&#x3C;input id=\"name\" class=\"form-control\"\n <a href=\"api/forms/FormControlName\" class=\"code-anchor\">formControlName</a>=\"name\" required >\n\n&#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"name.invalid &#x26;&#x26; (name.dirty || name.touched)\"\n class=\"alert alert-danger\">\n\n &#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"name.errors.required\">\n Name is required.\n &#x3C;/div>\n &#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"name.errors.minlength\">\n Name must be at least 4 characters long.\n &#x3C;/div>\n &#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"name.errors.forbiddenName\">\n Name cannot be Bob.\n &#x3C;/div>\n&#x3C;/div>\n\n</code-example>\n<p>This form differs from the template-driven version in that it no longer exports any directives. Instead, it uses the <code>name</code> getter defined in the component class.</p>\n<p>Notice that the <code>required</code> attribute is still present in the template. Although it's not necessary for validation, it should be retained to for accessibility purposes.</p>\n<a id=\"custom-validators\"></a>\n<h2 id=\"defining-custom-validators\">Defining custom validators<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#defining-custom-validators\"><i class=\"material-icons\">link</i></a></h2>\n<p>The built-in validators don't always match the exact use case of your application, so you sometimes need to create a custom validator.</p>\n<p>Consider the <code>forbiddenNameValidator</code> function from previous <a href=\"guide/form-validation#reactive-component-class\">reactive-form examples</a>.\nHere's what the definition of that function looks like.</p>\n<code-example path=\"form-validation/src/app/shared/forbidden-name.directive.ts\" region=\"custom-validator\" header=\"shared/forbidden-name.directive.ts (forbiddenNameValidator)\">\n/** A hero's name can't match the given regular expression */\nexport function forbiddenNameValidator(nameRe: RegExp): <a href=\"api/forms/ValidatorFn\" class=\"code-anchor\">ValidatorFn</a> {\n return (control: <a href=\"api/forms/AbstractControl\" class=\"code-anchor\">AbstractControl</a>): {[key: string]: any} | null => {\n const forbidden = nameRe.test(control.value);\n return forbidden ? {forbiddenName: {value: control.value}} : null;\n };\n}\n\n</code-example>\n<p>The function is a factory that takes a regular expression to detect a <em>specific</em> forbidden name and returns a validator function.</p>\n<p>In this sample, the forbidden name is \"bob\", so the validator will reject any hero name containing \"bob\".\nElsewhere it could reject \"alice\" or any name that the configuring regular expression matches.</p>\n<p>The <code>forbiddenNameValidator</code> factory returns the configured validator function.\nThat function takes an Angular control object and returns <em>either</em>\nnull if the control value is valid <em>or</em> a validation error object.\nThe validation error object typically has a property whose name is the validation key, <code>'forbiddenName'</code>,\nand whose value is an arbitrary dictionary of values that you could insert into an error message, <code>{name}</code>.</p>\n<p>Custom async validators are similar to sync validators, but they must instead return a Promise or observable that later emits null or a validation error object.\nIn the case of an observable, the observable must complete, at which point the form uses the last value emitted for validation.</p>\n<a id=\"adding-to-reactive-forms\"></a>\n<h3 id=\"adding-custom-validators-to-reactive-forms\">Adding custom validators to reactive forms<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#adding-custom-validators-to-reactive-forms\"><i class=\"material-icons\">link</i></a></h3>\n<p>In reactive forms, add a custom validator by passing the function directly to the <code><a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a></code>.</p>\n<code-example path=\"form-validation/src/app/reactive/hero-form-reactive.component.1.ts\" region=\"custom-validator\" header=\"reactive/hero-form-reactive.component.ts (validator functions)\">\nthis.heroForm = new <a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a>({\n name: new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(this.hero.name, [\n Validators.required,\n Validators.minLength(4),\n forbiddenNameValidator(/bob/i) // &#x3C;-- Here's how you pass in the custom validator.\n ]),\n alterEgo: new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(this.hero.alterEgo),\n power: new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(this.hero.power, Validators.required)\n});\n\n</code-example>\n<a id=\"adding-to-template-driven-forms\"></a>\n<h3 id=\"adding-custom-validators-to-template-driven-forms\">Adding custom validators to template-driven forms<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#adding-custom-validators-to-template-driven-forms\"><i class=\"material-icons\">link</i></a></h3>\n<p>In template-driven forms, add a directive to the template, where the directive wraps the validator function.\nFor example, the corresponding <code>ForbiddenValidatorDirective</code> serves as a wrapper around the <code>forbiddenNameValidator</code>.</p>\n<p>Angular recognizes the directive's role in the validation process because the directive registers itself with the <code><a href=\"api/forms/NG_VALIDATORS\" class=\"code-anchor\">NG_VALIDATORS</a></code> provider, as shown in the following example.\n<code><a href=\"api/forms/NG_VALIDATORS\" class=\"code-anchor\">NG_VALIDATORS</a></code> is a predefined provider with an extensible collection of validators.</p>\n<code-example path=\"form-validation/src/app/shared/forbidden-name.directive.ts\" region=\"directive-providers\" header=\"shared/forbidden-name.directive.ts (providers)\">\nproviders: [{provide: <a href=\"api/forms/NG_VALIDATORS\" class=\"code-anchor\">NG_VALIDATORS</a>, useExisting: ForbiddenValidatorDirective, multi: true}]\n\n</code-example>\n<p>The directive class then implements the <code><a href=\"api/forms/Validator\" class=\"code-anchor\">Validator</a></code> interface, so that it can easily integrate\nwith Angular forms.\nHere is the rest of the directive to help you get an idea of how it all\ncomes together.</p>\n<code-example path=\"form-validation/src/app/shared/forbidden-name.directive.ts\" region=\"directive\" header=\"shared/forbidden-name.directive.ts (directive)\">\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({\n selector: '[appForbiddenName]',\n providers: [{provide: <a href=\"api/forms/NG_VALIDATORS\" class=\"code-anchor\">NG_VALIDATORS</a>, useExisting: ForbiddenValidatorDirective, multi: true}]\n})\nexport class ForbiddenValidatorDirective implements <a href=\"api/forms/Validator\" class=\"code-anchor\">Validator</a> {\n @<a href=\"api/core/Input\" class=\"code-anchor\">Input</a>('appForbiddenName') forbiddenName: string;\n\n validate(control: <a href=\"api/forms/AbstractControl\" class=\"code-anchor\">AbstractControl</a>): <a href=\"api/forms/ValidationErrors\" class=\"code-anchor\">ValidationErrors</a> | null {\n return this.forbiddenName ? forbiddenNameValidator(new RegExp(this.forbiddenName, 'i'))(control)\n : null;\n }\n}\n\n</code-example>\n<p>Once the <code>ForbiddenValidatorDirective</code> is ready, you can add its selector, <code>appForbiddenName</code>, to any input element to activate it.\nFor example:</p>\n<code-example path=\"form-validation/src/app/template/hero-form-template.component.html\" region=\"name-input\" header=\"template/hero-form-template.component.html (forbidden-name-input)\">\n&#x3C;input id=\"name\" name=\"name\" class=\"form-control\"\n required <a href=\"api/forms/MinLengthValidator\" class=\"code-anchor\">minlength</a>=\"4\" appForbiddenName=\"bob\"\n [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"hero.name\" #name=\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\" >\n\n</code-example>\n<div class=\"alert is-helpful\">\n<p>Notice that the custom validation directive is instantiated with <code>useExisting</code> rather than <code>useClass</code>. The registered validator must be <em>this instance</em> of\nthe <code>ForbiddenValidatorDirective</code>—the instance in the form with\nits <code>forbiddenName</code> property bound to “bob\".</p>\n<p>If you were to replace <code>useExisting</code> with <code>useClass</code>, then youd be registering a new class instance, one that doesnt have a <code>forbiddenName</code>.</p>\n</div>\n<h2 id=\"control-status-css-classes\">Control status CSS classes<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#control-status-css-classes\"><i class=\"material-icons\">link</i></a></h2>\n<p>Angular automatically mirrors many control properties onto the form control element as CSS classes. You can use these classes to style form control elements according to the state of the form.\nThe following classes are currently supported.</p>\n<ul>\n<li><code>.ng-valid</code></li>\n<li><code>.ng-invalid</code></li>\n<li><code>.ng-pending</code></li>\n<li><code>.ng-pristine</code></li>\n<li><code>.ng-dirty</code></li>\n<li><code>.ng-untouched</code></li>\n<li><code>.ng-touched</code></li>\n</ul>\n<p>In the following example, the hero form uses the <code>.ng-valid</code> and <code>.ng-invalid</code> classes to\nset the color of each form control's border.</p>\n<code-example path=\"form-validation/src/assets/forms.css\" header=\"forms.css (status classes)\">\n\n.ng-valid[required], .ng-valid.required {\n border-left: 5px solid #42A948; /* green */\n}\n\n.ng-invalid:not(form) {\n border-left: 5px solid #a94442; /* red */\n}\n\n\n</code-example>\n<h2 id=\"cross-field-validation\">Cross-field validation<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#cross-field-validation\"><i class=\"material-icons\">link</i></a></h2>\n<p>A cross-field validator is a <a href=\"guide/form-validation#custom-validators\" title=\"Read about custom validators\">custom validator</a> that compares the values of different fields in a form and accepts or rejects them in combination.\nFor example, you might have a form that offers mutually incompatible options, so that if the user can choose A or B, but not both.\nSome field values might also depend on others; a user might be allowed to choose B only if A is also chosen.</p>\n<p>The following cross validation examples show how to do the following:</p>\n<ul>\n<li>Validate reactive or template-based form input based on the values of two sibling controls,</li>\n<li>Show a descriptive error message after the user interacted with the form and the validation failed.</li>\n</ul>\n<p>The examples use cross-validation to ensure that heroes do not reveal their true identities by filling out the Hero Form. The validators do this by checking that the hero names and alter egos do not match.</p>\n<h3 id=\"adding-cross-validation-to-reactive-forms\">Adding cross-validation to reactive forms<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#adding-cross-validation-to-reactive-forms\"><i class=\"material-icons\">link</i></a></h3>\n<p>The form has the following structure:</p>\n<code-example language=\"javascript\">\nconst heroForm = new <a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a>({\n 'name': new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(),\n 'alterEgo': new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(),\n 'power': new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>()\n});\n</code-example>\n<p>Notice that the <code>name</code> and <code>alterEgo</code> are sibling controls.\nTo evaluate both controls in a single custom validator, you must perform the validation in a common ancestor control: the <code><a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a></code>.\nYou query the <code><a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a></code> for its child controls so that you can compare their values.</p>\n<p>To add a validator to the <code><a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a></code>, pass the new validator in as the second argument on creation.</p>\n<code-example language=\"javascript\">\nconst heroForm = new <a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a>({\n 'name': new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(),\n 'alterEgo': new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>(),\n 'power': new <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>()\n}, { validators: identityRevealedValidator });\n</code-example>\n<p>The validator code is as follows.</p>\n<code-example path=\"form-validation/src/app/shared/identity-revealed.directive.ts\" region=\"cross-validation-validator\" header=\"shared/identity-revealed.directive.ts\">\n/** A hero's name can't match the hero's alter ego */\nexport const identityRevealedValidator: <a href=\"api/forms/ValidatorFn\" class=\"code-anchor\">ValidatorFn</a> = (control: <a href=\"api/forms/AbstractControl\" class=\"code-anchor\">AbstractControl</a>): <a href=\"api/forms/ValidationErrors\" class=\"code-anchor\">ValidationErrors</a> | null => {\n const name = control.get('name');\n const alterEgo = control.get('alterEgo');\n\n return name &#x26;&#x26; alterEgo &#x26;&#x26; name.value === alterEgo.value ? { identityRevealed: true } : null;\n};\n\n</code-example>\n<p>The <code>identity</code> validator implements the <code><a href=\"api/forms/ValidatorFn\" class=\"code-anchor\">ValidatorFn</a></code> interface. It takes an Angular control object as an argument and returns either null if the form is valid, or <code><a href=\"api/forms/ValidationErrors\" class=\"code-anchor\">ValidationErrors</a></code> otherwise.</p>\n<p>The validator retrieves the child controls by calling the <code><a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a></code>'s <a href=\"api/forms/AbstractControl#get\">get</a> method, then compares the values of the <code>name</code> and <code>alterEgo</code> controls.</p>\n<p>If the values do not match, the hero's identity remains secret, both are valid, and the validator returns null.\nIf they do match, the hero's identity is revealed and the validator must mark the form as invalid by returning an error object.</p>\n<p>To provide better user experience, the template shows an appropriate error message when the form is invalid.</p>\n<code-example path=\"form-validation/src/app/reactive/hero-form-reactive.component.html\" region=\"cross-validation-error-message\" header=\"reactive/hero-form-template.component.html\">\n&#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"heroForm.errors?.identityRevealed &#x26;&#x26; (heroForm.touched || heroForm.dirty)\" class=\"cross-validation-error-message alert alert-danger\">\n Name cannot match alter ego.\n&#x3C;/div>\n\n</code-example>\n<p>This <code>*<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a></code> displays the error if the <code><a href=\"api/forms/FormGroup\" class=\"code-anchor\">FormGroup</a></code> has the cross validation error returned by the <code>identityRevealed</code> validator, but only if the user has finished <a href=\"guide/form-validation#dirty-or-touched\">interacting with the form</a>.</p>\n<h3 id=\"adding-cross-validation-to-template-driven-forms\">Adding cross-validation to template-driven forms<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#adding-cross-validation-to-template-driven-forms\"><i class=\"material-icons\">link</i></a></h3>\n<p>For a template-driven form, you must create a directive to wrap the validator function.\nYou provide that directive as the validator using the <a href=\"guide/form-validation#adding-to-template-driven-forms\" title=\"Read about providing validators\"><code>NG_VALIDATORS</code> token</a>, as shown in the following example.</p>\n<code-example path=\"form-validation/src/app/shared/identity-revealed.directive.ts\" region=\"cross-validation-directive\" header=\"shared/identity-revealed.directive.ts\">\n@<a href=\"api/core/Directive\" class=\"code-anchor\">Directive</a>({\n selector: '[appIdentityRevealed]',\n providers: [{ provide: <a href=\"api/forms/NG_VALIDATORS\" class=\"code-anchor\">NG_VALIDATORS</a>, useExisting: IdentityRevealedValidatorDirective, multi: true }]\n})\nexport class IdentityRevealedValidatorDirective implements <a href=\"api/forms/Validator\" class=\"code-anchor\">Validator</a> {\n validate(control: <a href=\"api/forms/AbstractControl\" class=\"code-anchor\">AbstractControl</a>): <a href=\"api/forms/ValidationErrors\" class=\"code-anchor\">ValidationErrors</a> {\n return identityRevealedValidator(control);\n }\n}\n\n</code-example>\n<p>You must add the new directive to the HTML template.\nBecause the validator must be registered at the highest level in the form, the following template puts the directive on the <code>form</code> tag.</p>\n<code-example path=\"form-validation/src/app/template/hero-form-template.component.html\" region=\"cross-validation-register-validator\" header=\"template/hero-form-template.component.html\">\n&#x3C;form #heroForm=\"<a href=\"api/forms/NgForm\" class=\"code-anchor\">ngForm</a>\" appIdentityRevealed>\n\n</code-example>\n<p>To provide better user experience, we show an appropriate error message when the form is invalid.</p>\n<code-example path=\"form-validation/src/app/template/hero-form-template.component.html\" region=\"cross-validation-error-message\" header=\"template/hero-form-template.component.html\">\n&#x3C;div *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"heroForm.errors?.identityRevealed &#x26;&#x26; (heroForm.touched || heroForm.dirty)\" class=\"cross-validation-error-message alert alert-danger\">\n Name cannot match alter ego.\n&#x3C;/div>\n\n</code-example>\n<p>This is the same in both template-driven and reactive forms.</p>\n<h2 id=\"creating-asynchronous-validators\">Creating asynchronous validators<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#creating-asynchronous-validators\"><i class=\"material-icons\">link</i></a></h2>\n<p>Asynchronous validators implement the <code><a href=\"api/forms/AsyncValidatorFn\" class=\"code-anchor\">AsyncValidatorFn</a></code> and <code><a href=\"api/forms/AsyncValidator\" class=\"code-anchor\">AsyncValidator</a></code> interfaces.\nThese are very similar to their synchronous counterparts, with the following differences.</p>\n<ul>\n<li>The <code>validate()</code> functions must return a Promise or an observable,</li>\n<li>The observable returned must be finite, meaning it must complete at some point.\nTo convert an infinite observable into a finite one, pipe the observable through a filtering operator such as <code>first</code>, <code>last</code>, <code>take</code>, or <code>takeUntil</code>.</li>\n</ul>\n<p>Asynchronous validation happens after the synchronous validation, and is performed only if the synchronous validation is successful.\nThis check allows forms to avoid potentially expensive async validation processes (such as an HTTP request) if the more basic validation methods have already found invalid input.</p>\n<p>After asynchronous validation begins, the form control enters a <code>pending</code> state. You can inspect the control's <code>pending</code> property and use it to give visual feedback about the ongoing validation operation.</p>\n<p>A common UI pattern is to show a spinner while the async validation is being performed. The following example shows how to achieve this in a template-driven form.</p>\n<code-example language=\"html\">\n&#x3C;input [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"name\" #model=\"<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>\" appSomeAsyncValidator>\n&#x3C;app-spinner *<a href=\"api/common/NgIf\" class=\"code-anchor\">ngIf</a>=\"model.pending\">&#x3C;/app-spinner>\n</code-example>\n<h3 id=\"implementing-a-custom-async-validator\">Implementing a custom async validator<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#implementing-a-custom-async-validator\"><i class=\"material-icons\">link</i></a></h3>\n<p>In the following example, an async validator ensures that heroes pick an alter ego that is not already taken.\nNew heroes are constantly enlisting and old heroes are leaving the service, so the list of available alter egos cannot be retrieved ahead of time.\nTo validate the potential alter ego entry, the validator must initiate an asynchronous operation to consult a central database of all currently enlisted heroes.</p>\n<p>The following code create the validator class, <code>UniqueAlterEgoValidator</code>, which implements the <code><a href=\"api/forms/AsyncValidator\" class=\"code-anchor\">AsyncValidator</a></code> interface.</p>\n<code-example path=\"form-validation/src/app/shared/alter-ego.directive.ts\" region=\"async-validator\">\n@<a href=\"api/core/Injectable\" class=\"code-anchor\">Injectable</a>({ providedIn: 'root' })\nexport class UniqueAlterEgoValidator implements <a href=\"api/forms/AsyncValidator\" class=\"code-anchor\">AsyncValidator</a> {\n constructor(private heroesService: HeroesService) {}\n\n validate(\n ctrl: <a href=\"api/forms/AbstractControl\" class=\"code-anchor\">AbstractControl</a>\n ): Promise&#x3C;<a href=\"api/forms/ValidationErrors\" class=\"code-anchor\">ValidationErrors</a> | null> | Observable&#x3C;<a href=\"api/forms/ValidationErrors\" class=\"code-anchor\">ValidationErrors</a> | null> {\n return this.heroesService.isAlterEgoTaken(ctrl.value).pipe(\n map(isTaken => (isTaken ? { uniqueAlterEgo: true } : null)),\n catchError(() => of(null))\n );\n }\n}\n\n</code-example>\n<p>The constructor injects the <code>HeroesService</code>, which defines the following interface.</p>\n<code-example language=\"typescript\">\ninterface HeroesService {\n isAlterEgoTaken: (alterEgo: string) => Observable&#x3C;boolean>;\n}\n</code-example>\n<p>In a real world application, the <code>HeroesService</code> would be responsible for making an HTTP request to the hero database to check if the alter ego is available.\nFrom the validator's point of view, the actual implementation of the service is not important, so the example can just code against the <code>HeroesService</code> interface.</p>\n<p>As the validation begins, the <code>UniqueAlterEgoValidator</code> delegates to the <code>HeroesService</code> <code>isAlterEgoTaken()</code> method with the current control value.\nAt this point the control is marked as <code>pending</code> and remains in this state until the observable chain returned from the <code>validate()</code> method completes.</p>\n<p>The <code>isAlterEgoTaken()</code> method dispatches an HTTP request that checks if the alter ego is available, and returns <code>Observable&#x3C;boolean></code> as the result.\nThe <code>validate()</code> method pipes the response through the <code>map</code> operator and transforms it into a validation result.</p>\n<p>The method then, like any validator, returns <code>null</code> if the form is valid, and <code><a href=\"api/forms/ValidationErrors\" class=\"code-anchor\">ValidationErrors</a></code> if it is not.\nThis validator handles any potential errors with the <code>catchError</code> operator.\nIn this case, the validator treats the <code>isAlterEgoTaken()</code> error as a successful validation, because failure to make a validation request does not necessarily mean that the alter ego is invalid.\nYou could handle the error differently and return the <code>ValidationError</code> object instead.</p>\n<p>After some time passes, the observable chain completes and the asynchronous validation is done.\nThe <code>pending</code> flag is set to <code>false</code>, and the form validity is updated.</p>\n<h3 id=\"optimizing-performance-of-async-validators\">Optimizing performance of async validators<a title=\"Link to this heading\" class=\"header-link\" aria-hidden=\"true\" href=\"guide/form-validation#optimizing-performance-of-async-validators\"><i class=\"material-icons\">link</i></a></h3>\n<p>By default, all validators run after every form value change. With synchronous validators, this does not normally have a noticeable impact on application performance.\nAsync validators, however, commonly perform some kind of HTTP request to validate the control. Dispatching an HTTP request after every keystroke could put a strain on the backend API, and should be avoided if possible.</p>\n<p>You can delay updating the form validity by changing the <code>updateOn</code> property from <code>change</code> (default) to <code>submit</code> or <code>blur</code>.</p>\n<p>With template-driven forms, set the property in the template.</p>\n<code-example language=\"html\">\n&#x3C;input [(<a href=\"api/forms/NgModel\" class=\"code-anchor\">ngModel</a>)]=\"name\" [ngModelOptions]=\"{updateOn: 'blur'}\">\n</code-example>\n<p>With reactive forms, set the property in the <code><a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a></code> instance.</p>\n<code-example language=\"typescript\">\nnew <a href=\"api/forms/FormControl\" class=\"code-anchor\">FormControl</a>('', {updateOn: 'blur'});\n</code-example>\n\n \n</div>\n\n<!-- links to this doc:\n - api/forms/CheckboxRequiredValidator\n - api/forms/EmailValidator\n - api/forms/MaxLengthValidator\n - api/forms/MaxValidator\n - api/forms/MinLengthValidator\n - api/forms/MinValidator\n - api/forms/PatternValidator\n - api/forms/RequiredValidator\n - guide/dynamic-form\n - guide/example-apps-list\n - guide/forms-overview\n - guide/glossary\n - guide/reactive-forms\n-->\n<!-- links from this doc:\n - api/common/NgIf\n - api/core/Directive\n - api/core/Injectable\n - api/core/Input\n - api/forms/AbstractControl\n - api/forms/AbstractControl#get\n - api/forms/AsyncValidator\n - api/forms/AsyncValidatorFn\n - api/forms/FormControl\n - api/forms/FormControlName\n - api/forms/FormGroup\n - api/forms/MinLengthValidator\n - api/forms/NG_VALIDATORS\n - api/forms/NgForm\n - api/forms/NgModel\n - api/forms/ValidationErrors\n - api/forms/Validator\n - api/forms/ValidatorFn\n - api/forms/Validators\n - guide/architecture\n - guide/form-validation#adding-cross-validation-to-reactive-forms\n - guide/form-validation#adding-cross-validation-to-template-driven-forms\n - guide/form-validation#adding-custom-validators-to-reactive-forms\n - guide/form-validation#adding-custom-validators-to-template-driven-forms\n - guide/form-validation#adding-to-template-driven-forms\n - guide/form-validation#built-in-validator-functions\n - guide/form-validation#control-status-css-classes\n - guide/form-validation#creating-asynchronous-validators\n - guide/form-validation#cross-field-validation\n - guide/form-validation#custom-validators\n - guide/form-validation#defining-custom-validators\n - guide/form-validation#dirty-or-touched\n - guide/form-validation#implementing-a-custom-async-validator\n - guide/form-validation#optimizing-performance-of-async-validators\n - guide/form-validation#reactive-component-class\n - guide/form-validation#validating-form-input\n - guide/form-validation#validating-input-in-reactive-forms\n - guide/form-validation#validating-input-in-template-driven-forms\n - guide/form-validation#validator-functions\n - guide/forms\n - guide/forms-overview\n - guide/reactive-forms\n - https://developer.mozilla.org/en-US/docs/Web/Guide/HTML/HTML5/Constraint_validation\n - https://github.com/angular/angular/edit/master/aio/content/guide/form-validation.md?message=docs%3A%20describe%20your%20change...\n - https://www.typescriptlang.org/\n-->"
}