include ../_util-fns :marked We can improve overall data quality by validating user input for accuracy and completeness. In this cookbook we show 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. An Angular component consists of a template and a component class containing the code that drives the template. The first example demonstrates input validation entirely within the template. The second example moves the validation logic out of the template and into the component class, giving the developer more control and easier unit testing. Both examples are based on the the sample form in the [Forms chapter.](../guide/forms.html) :marked ## Contents [Template-Driven Forms Approach](#template-driven) [Reactive Forms Approach](#reactive) **Try the live example** .l-main-section :marked ## Template-Driven Forms In the template-driven approach, each control on the form defines its own validation and validation messages in the template. Here's an excerpt from the template html for a single input box control bound to the hero name: +makeExample('cb-form-validation/ts/app/template/hero-form-template.component.html','name-with-error-msg','app/template/hero-form-template.component.html (Hero name)') :marked Note the following: - The `` element implements the validation rules as HTML validation attributes: `required`, `minlength`, and `maxlength`. - Set the `name` attribute of the input box so Angular can track this input element. - The `[(ngModel)]` two-way data binding to the hero's name in the `model.name` property also registers the input box as a control associated with the implicit `NgForm` directive. - A template variable (`#name`) is a reference to this control. that we can check for control states such as `valid` or `dirty`. The template variable value is always `ngModel`. - A `
` element for a group of validation error messages. The `*ngIf` reveals the error group if there are any errors and the control is either `dirty` or `touched`. - Within the error group are separate `
` elements for each possible validation error. Here we've prepared messages for `required`, `minlength`, and `maxlength`. The full template repeats this kind of layout for each data entry control on the form. .l-sub-section :marked 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. Learn about `dirty` and `touched` in the [Forms](../guide/forms.html) chapter. :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-template.component.ts','class','app/template/hero-form-template.component.ts') :marked Use this template-driven validation technique when working with simple forms with simple validation scenarios. Here are the pertinent files for the template-driven approach: +makeTabs( `cb-form-validation/ts/app/template/hero-form-template.module.ts, cb-form-validation/ts/app/template/hero-form-template.component.html, cb-form-validation/ts/app/template/hero-form-template.component.ts, cb-form-validation/ts/app/shared/hero.ts, cb-form-validation/ts/app/shared/submitted.component.ts`, '', `app/template/hero-form-template.module.ts, app/template/hero-form-template.component.html, app/template/hero-form-template.component.ts, app/shared/hero.ts, app/shared/submitted.component.ts`) .l-main-section :marked ## Reactive Forms Reactive forms are an alternate approach to form validation in the validation rules are specified in the model as defined in the component class. Defining the validation in the class instead of the template gives you more control. You can adjust the validation based on the application state or user. Your code then becomes the source of truth for your validation. We also remove the data binding (`ngModel`) and validation messages from the template. This means that we need to set the default value for each control, and we need to add code that tracks the user's changes so we can hide/show validation messages as needed. .alert.is-important :marked When moving the validation attributes out of the HTML, we are no longer aria ready. Work is being done to address this. +makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts','class','app/reactive/hero-form-reactive.component.ts') :marked In the component's class, we define the form and our own data structures to manage definition and display of the validation messages: - Declare a property for the form typed as a `FormGroup`. - Declare a property for a collection that contains the *current* validation messages to display to the user. We'll initialize this collection with one entry for each control. We'll update this collection with appropriate validation messages when validation rules are broken. - Declare a property for a collection that contains the set of *possible* validation messages. We'll initialize this collection with all of the possible validation messages for each control. - Add a constructor for the class and use dependency injection to inject in the `FormBuilder` service. We use that service to build the form. - In the constructor, initialize the collections. - The `formError` collection is initialized using the control name as the key and the current validation message as the value. When the form is first displayed, no validation messages should appear, so the current validation message for each control is empty. - The `validationMessages` collection is initialized using the control name as the key and the set of possible validation messages as the value. For this example, we hard-code in the set of validation messages. But you can retrieve these messages from an external file or from a database table. Alternatively, you could build a service that retrieved and managed the set of validation messsages. - Build a method to create the form. We name this method `buildForm` in our example. The form is created in a method so it can be called again to reset the form with different default values when adding a new hero. - In the `buildForm` method, group the controls defined for the form using the `FormBuilder` instance. Here we define each control's name, default value, and validation rules. - We call this `buildForm` method from the `ngOnInit` lifecycle hook method. But in many applications, you may need to call `buildForm` from somewhere else. For example, if the default values are coming from an http request, call the `buildForm` method after the data is retrieved. .l-sub-section :marked Learn more about `ngOnInit` in the [LifeCycle Hooks](../guide/lifecycle-hooks.html) chapter. :marked There is one more important thing that we need to do. We need to watch for any changes that the user makes and adjust the validation messages appropriately. For example, if the user enters a single character into the name field, we need to change the validation message from `Name is required` to `Name must be at least 4 characters long`. And when the user enters the fourth character, we need to remove the message entirely. To watch for changes, we add one additional statement to the `buildForm` method. We subscribe to the built-in `FormGroup`'s `valueChanges` observable. Each time any control on the form is changed by the user, we receive a notification. In our example, we then call an `onValueChanged` method to reset the validation messages. In the `onValueChanged` method, we: - Loop through each entry in the `formError` collection. - Determine whether the control has an error using the control's properties and our business rules. In our example we define that a control has an error if the control is dirty and not valid. - We clear any prior validation messages. - If the control has a validation error, we loop through the errors collection and concatenate the appropriate validation messages into one message for display to the user. We'll use the form and `formError` collection properties in the template. Notice that when using the reactive forms approach, the amount of code required for each control in the template is signficantly reduced. +makeExample('cb-form-validation/ts/app/reactive/hero-form-reactive.component.html','name-with-error-msg','app/reactive/hero-form-reactive.component.html') :marked In the template, define a standard label and set up an input box for validation as follows: - Set the `formControlName` directive to the name of the control as defined in the `FormBuilder`'s `group` method, `name` in this example. In this example we also used `ngClass` to set a style on required fields. This is optional and based on the styling you select for your application. In the `div` element for the validation messages, we use the validation messages collection (`formError` in this example) to determine whether to display a validation message. - We use `*ngIf` to check whether the control has a validation message in the collection. - If so, we display it to the user using interpolation. Repeat for each data entry control on the form. The template then has no validation logic. If there is a validation message in the collection it displays it, if not it doesn't. All of the logic is in the component class. Use this technique when you want better control over the validation rules and messsages. Here are the pertinent files for the reactive forms approach: +makeTabs( `cb-form-validation/ts/app/reactive/hero-form-reactive.module.ts, cb-form-validation/ts/app/reactive/hero-form-reactive.component.html, cb-form-validation/ts/app/reactive/hero-form-reactive.component.ts, cb-form-validation/ts/app/shared/hero.ts, cb-form-validation/ts/app/shared/submitted.component.ts`, '', `app/reactive/hero-form-reactive.module.ts, app/reactive/hero-form-reactive.component.html, app/reactive/hero-form-reactive.component.ts, app/shared/hero.ts, app/shared/submitted.component.ts`) :marked [Back to top](#top)