Validating Forms
Overview
It’s important to validate user input as soon as possible, pointing out any errors they need to correct.
There are three types of errors that we need to validate:
Field-level validation errors
Most validation errors apply to individual fields in the form. Display these validation errors beneath the field’s input. The field label and input border turn red to indicate the error status.
Field-level validation errors don’t display until after the user has either changed the field or submitted the form. This gives the user a chance to provide input for a field before we flag it as invalid. This is especially important for cases where the initial field value is invalid, as is often the case when adding a new record.
Try to catch as many validation errors in the client (browser) as possible before your application posts the form data to the server. This saves time for the user and saves network and server resources. For example, catch places where a required field is missing, or a field doesn’t follow the required format, like an e-mail address, etc. The server must still perform all of the same validation checks; it should never assume that the client caught any validation errors.
However, some validation errors can only be caught at the server, after the client has posted the form data to the server. These validations depend on business logic and/or data only available at the server. Display server validation errors below the field, just like we do with client validation errors.
Cross-field validation errors
Cross-field validation errors occur when the value for two or more fields in the form are valid separately but are invalid when combined. For example, the value provided for an Expiration Date field may be valid on its own, and the value provided for an Effective Date field may also be valid on its own, but if the value specified for the Expiration Date is before the value specified for the Effective Date, the combination of the two values is invalid.
When this happens, display the validation error beneath the input for each corresponding field. This keeps the error message close to each of the affected fields. The field label and input border turn red to indicate the error status. You can either repeat the same validation error beneath all affected fields, or display slight variations of the same validation error that are centric to that field.
Form-level validation errors
In less common cases, there can be validation errors for the entire form rather than for an individual field. These validation errors display at the top of the form, between the Save/Cancel buttons and the first field in the form.
In cases where you get field-level validation errors from the server that don’t identify the individual fields, you can display these as form-level validation errors, although this can make the user work harder to figure out which field to correct.
Do not display cross-field validation errors as form-level validation errors. Display these as field-level validation errors, so that the error message displays close to each affected field.
Navigating through field-level validation errors
It’s important to make it easy for the user to find and fix validation errors in a form’s inputs.
This is less of a problem with small forms, since the fields and any validation errors are mostly visible at a glance. But if the form contains a large number of fields, the user sees less fields at a time, which can make it difficult for the user to know where the field-level validation errors are.
And that’s if the user even knows that there are validation errors in the first place. If all fields with validation errors are currently scrolled out of view, the only clue that the user has that validation errors exist is the fact that the Save button is disabled.
The validation error navigator helps solve these problems.
- Add the validation error navigator to the display block toolbar and the floating toolbar. It’s visible whenever the form contains any field-level validation errors and hides when there are no validation errors in the form.
- The validation error navigator specifies the number of validation errors present in the form. Its very presence is a reliable indicator to the user that the form contains validation errors.
- The validation error navigator includes arrow buttons for navigating between validation errors. Pressing the “next” button scrolls to and sets focus to the next validation error in the form. The “back” button does the same for the previous validation error in the form.
The validation error navigator must appear to the right of all other buttons in the toolbar. The typical order (left to right) will be Save button, Cancel button, then the validation error navigator.
The validation error navigator does not reproduce the list of validation errors, it simply alerts the user to the fact that the form contains validation errors and helps the user navigate to and fix each validation error.
Development
Web component development
Component reference
jha-validation-error-navigator
Displays navigational buttons to jump to previous/next form inputs currently failing validation
Name | Type | Default | Description |
---|---|---|---|
jhaForm | FormGroup | new FormGroup({}) | Bind this to the name of the FormGroup in your view. This is used to iterate through the form components and create an array of those with validation errors. |
jhaManualErrorList | Array<String> | [] | Bind this property to an array of formControlName strings to manually include as errors in the error navigator. |
jhaErrorNavigation | event | Event handler that fires when the user hits the previous or next button. When clicked this event sends an argument of the formControlName. Create an event handler that accepts a string. Use this handler to set focus on the form element with the supplied formControlName. | |
jhaCustomValidationMappings | Array<JhaCustomValidationMap> | [] | If your form uses custom form validators, bind this property to an array of JhaCustomValidationMap objects in your TypeScript. The JhaCustomValidationMap class contains two properties - name: string, formControlNames: string[]. |
Implementation
The validation error handling supported by Responsive UI uses the validation functionality built into Angular. Be sure to thoroughly read the Angular validation information here first: https://angular.io/guide/form-validation.
Angular includes several useful built-in validators for the most common validation cases like required field, min/max value, min/max length, pattern (for regular expression field values like a tax ID number or phone number), and email. But these obviously can’t cover every validation use case your app will need, so you’re able to create your own custom validators as well.
We strongly recommend using reactive forms, but you can also use template-driven forms if needed. Both are supported, although be aware that all of our examples and samples use reactive forms.
Imports
First, import FormsModule
and ReactiveFormsModule
in app.module.ts.
In the TypeScript that backs the form, import FormGroup
, FormControl
, and Validators
.
Defining the Form
Define the form, its fields, and the validators for each field (if any) in the TypeScript. Create a FormGroup
for the form and a FormControl
for each field, passing in the initial value for the field as well as zero or more validators.
In this example, the name, ssn, birthdate, street, city, state, zip, and country fields are all required, so we add the required validator for each. The interestRate field has min and max validators and the zip field has a pattern (regex) validator. While Angular supports several built-in validators, you can also create custom validators. The last argument to the FormGroup
constructor wires up the CountryAddressTypeValidator
(a custom validation directive) as a cross-field validator. This particular validator looks at more than one field, so it runs at the form level instead of the individual field level.
Next, create a property for each of the form fields to make it easier to interact with each of them in the HTML.
Form HTML
Define the form element in the HTML, binding the formGroup
attribute to the FormGroup
variable you defined in the TypeScript (editForm in this case). Wire up a submit event handler.
Save/Cancel Buttons
Add Save and Cancel buttons for the form. The Save button is a submit button that is disabled any time the editForm is invalid (i.e. when [disabled]="!editForm.valid"
). The Cancel button is a regular button that calls a method to abandon the form changes when pressed.
At a minimum you’ll add the Save and Cancel buttons to the display block toolbar, but you should also add them to a floating toolbar if the form is long. The floating toolbar displays after the user scrolls down the page a bit, so having the Save/Cancel buttons in the floating toolbar makes them available to the user no matter how far down they scroll.
Field-Level Validation Errors
See Editing Forms for information on how to set up form fields, including field-level validation errors.
Form-Level Validation Errors
Display form-level validations at the top of the form, between the Save/Cancel buttons and the form elements.
- Wrap the form-level validation errors in an error inline notification
- We display validation errors only if the user has changed or visited the form’s fields, which we test with the Angular attributes
editForm.dirty
andeditForm.touched
.
Validation Error Navigator
The jha-validation-error-navigator
allows users to easily go to the previous/next validation error by clicking on the navigator arrows. Clicking the arrows fires an event, which you will need to handle to set focus on the correct form component.
Import the JhaFormsModule
using the .forRoot() method to inject the validator service.
In this example, we’re using the form component id
attribute to find the correct element. This means your form component elements will need to relate their formControlName attributes with the id attributes. To do so, take the formControlName
of the input and append 'field-'
to create your id.
If the form includes a FormArray
, the string returned from the error navigator will include the FormArray name followed by a dash and an index to highlight the correct input (example: teachers-0). For cases like this, construct your element id to include the index. If the FormArray contains FormGroups around the FormControls, the string returned will include the formArrayName
followed by a dash and the formGroupName
followed by a dash and the formControlName
of the input (example: teachers-0-name).
Once the form is set up, add a jha-validation-error-navigator
component to the rui-toolbar within the form’s display block. Bind the jhaForm
property to your FormGroup and bind the jhaErrorNavigation
property to a newly created event handler. If your form uses custom form validators, bind an array of JhaCustomValidationMap
elements to the jhaCustomValidationMappings
property.
If the view uses a rui-floating-toolbar
, add a jha-validation-error-navigator
component with the same properties and values.
In your event handler, accept a string argument to capture the formControlName of the input where focus should be applied. This handler will call a method to apply that focus.
If you’re using a large form within a wizard or accordion group boxes, there are additional steps that need to be taken to navigate the user to the correct step or group box before focusing on the form component. You can find details on the additional coding needed in Large Forms.
Next, create a method to apply focus to the desired input. Find the form component by using the constructed id. Then test if the element has any children inputs (this would be the case for custom components such as p-calendar
, p-checkbox
, etc.) and assign focus to the first child input, or (else) this element is a standard html element an assign focus to it directly.
And finally, create a public property populated with any custom validators used in the form. Import the JhaCustomValidationMap
class, then create an array with the name of the error thrown by the validator, followed by an array of the formControlName
values of the fields that need to be addressed in the validation error.
Angular wrapper development
Wrapper reference
jha-validation-error-navigator
Displays navigational buttons to jump to previous/next form inputs currently failing validation
Name | Type | Default | Description |
---|---|---|---|
jhaForm | FormGroup | new FormGroup({}) | Bind this to the name of the FormGroup in your view. This is used to iterate through the form components and create an array of those with validation errors. |
jhaManualErrorList | Array<String> | [] | Bind this property to an array of formControlName strings to manually include as errors in the error navigator. |
jhaErrorNavigation | event | Event handler that fires when the user hits the previous or next button. When clicked this event sends an argument of the formControlName. Create an event handler that accepts a string. Use this handler to set focus on the form element with the supplied formControlName. | |
jhaCustomValidationMappings | Array<JhaCustomValidationMap> | [] | If your form uses custom form validators, bind this property to an array of JhaCustomValidationMap objects in your TypeScript. The JhaCustomValidationMap class contains two properties - name: string, formControlNames: string[]. |
Implementation
The validation error handling supported by Responsive UI uses the validation functionality built into Angular. Be sure to thoroughly read the Angular validation information here first: https://angular.io/guide/form-validation.
Angular includes several useful built-in validators for the most common validation cases like required field, min/max value, min/max length, pattern (for regular expression field values like a tax ID number or phone number), and email. But these obviously can’t cover every validation use case your app will need, so you’re able to create your own custom validators as well.
We strongly recommend using reactive forms, but you can also use template-driven forms if needed. Both are supported, although be aware that all of our examples and samples use reactive forms.
Imports
First, import FormsModule
and ReactiveFormsModule
in app.module.ts.
In the TypeScript that backs the form, import FormGroup
, FormControl
, and Validators
.
Defining the Form
Define the form, its fields, and the validators for each field (if any) in the TypeScript. Create a FormGroup
for the form and a FormControl
for each field, passing in the initial value for the field as well as zero or more validators.
In this example, the name, ssn, birthdate, street, city, state, zip, and country fields are all required, so we add the required validator for each. The interestRate field has min and max validators and the zip field has a pattern (regex) validator. While Angular supports several built-in validators, you can also create custom validators. The last argument to the FormGroup
constructor wires up the CountryAddressTypeValidator
(a custom validation directive) as a cross-field validator. This particular validator looks at more than one field, so it runs at the form level instead of the individual field level.
Next, create a property for each of the form fields to make it easier to interact with each of them in the HTML.
Form HTML
Define the form element in the HTML, binding the formGroup
attribute to the FormGroup
variable you defined in the TypeScript (editForm in this case). Wire up a submit event handler.
Save/Cancel Buttons
Add Save and Cancel buttons for the form. The Save button is a submit button that is disabled any time the editForm is invalid (i.e. when [disabled]="!editForm.valid"
). The Cancel button is a regular button that calls a method to abandon the form changes when pressed.
At a minimum you’ll add the Save and Cancel buttons to the display block toolbar, but you should also add them to a floating toolbar if the form is long. The floating toolbar displays after the user scrolls down the page a bit, so having the Save/Cancel buttons in the floating toolbar makes them available to the user no matter how far down they scroll.
Field-Level Validation Errors
See Editing Forms for information on how to set up form fields, including field-level validation errors.
Form-Level Validation Errors
Display form-level validations at the top of the form, between the Save/Cancel buttons and the form elements.
- Wrap the form-level validation errors in an error inline notification
- We display validation errors only if the user has changed or visited the form’s fields, which we test with the Angular attributes
editForm.dirty
andeditForm.touched
.
Validation Error Navigator
The jha-validation-error-navigator
allows users to easily go to the previous/next validation error by clicking on the navigator arrows. Clicking the arrows fires an event, which you will need to handle to set focus on the correct form component.
Import the JhaFormsModule
using the .forRoot() method to inject the validator service.
In this example, we’re using the form component id
attribute to find the correct element. This means your form component elements will need to relate their formControlName attributes with the id attributes. To do so, take the formControlName
of the input and append 'field-'
to create your id.
If the form includes a FormArray
, the string returned from the error navigator will include the FormArray name followed by a dash and an index to highlight the correct input (example: teachers-0). For cases like this, construct your element id to include the index. If the FormArray contains FormGroups around the FormControls, the string returned will include the formArrayName
followed by a dash and the formGroupName
followed by a dash and the formControlName
of the input (example: teachers-0-name).
Once the form is set up, add a jha-validation-error-navigator
component to the jha-display-block-toolbar within the form’s display block. Bind the jhaForm
property to your FormGroup and bind the jhaErrorNavigation
property to a newly created event handler. If your form uses custom form validators, bind an array of JhaCustomValidationMap
elements to the jhaCustomValidationMappings
property.
If the view uses a jha-floating-toolbar
, add a jha-validation-error-navigator
component with the same properties and values.
In your event handler, accept a string argument to capture the formControlName of the input where focus should be applied. This handler will call a method to apply that focus.
If you’re using a large form within a wizard or accordion group boxes, there are additional steps that need to be taken to navigate the user to the correct step or group box before focusing on the form component. You can find details on the additional coding needed in Large Forms.
Next, create a method to apply focus to the desired input. Find the form component by using the constructed id. Then test if the element has any children inputs (this would be the case for custom components such as p-calendar
, p-checkbox
, etc.) and assign focus to the first child input, or (else) this element is a standard html element an assign focus to it directly.
And finally, create a public property populated with any custom validators used in the form. Import the JhaCustomValidationMap
class, then create an array with the name of the error thrown by the validator, followed by an array of the formControlName
values of the fields that need to be addressed in the validation error.
Design
Figma design
Dev Component | Design Component Name |
---|---|
Validation error navigator | RUI / Forms / Validation Error Navigator |
Text input with validation error | RUI / Forms / Text Input; select “Error” as the value for the State property |
Field-level validation error text | RUI / Forms / Validation Error |
Design documents typically do not show validation errors. That information is usually conveyed in a separate design artifact.
If you still need to display validation errors in your design, you can do the following:
- Add a validation error navigator to the display block toolbar, to the right of the Save and Cancel buttons.
- Separate the Save and Cancel buttons from the validation error navigator with a display block toolbar separator.
- For every field for which you’re showing a validation:
- Add a validation error component below the input component that contains the appropriate validation error text. Change its text to display the appropriate validation error text.
- Select the field label and apply the “rui-pacific/text-error” color style to it.
- Specify a value of “Error” for the State property in the field’s input component.
Adobe XD design
- Sample App - Validating Form Data
Dev Component | Design Component Name |
---|---|
Validation error navigator | JHA / Forms / Validation Error Navigator |
Design documents typically do not show validation errors. That information is usually conveyed in a separate design artifact.
If you still need to display validation errors in your design, you can do the following:
- Add a validation error navigator to the display block toolbar, to the right of the Save and Cancel buttons.
- Separate the Save and Cancel buttons from the validation error navigator with a display block toolbar separator.
- For every field for which you’re showing a validation:
- Add help text below the input component that contains the appropriate validation error text.
- Select the field label, the required field indicator (if present), and the help text.
- Search for the JHA / Color / Text / Error color asset in the Assets panel. Click the color asset or right-click it and select Apply as Fill to apply the error color to the field label, required field indicator, and help text.
- Select the input component.
- Right-click the error color asset and select Apply as Border to apply the error color as the input component’s border.