Form validation is an essential aspect of web development, especially when building applications with Angular. It ensures that the user enters data in the correct format, helping to avoid errors and improve the overall user experience.
When creating forms in Angular, it's important to provide feedback to the user on any errors in the form. This feedback can take the form of error messages that appear next to form controls when the user has entered invalid data.
The benefits of implementing a reusable validation message solution
Having a generic solution for displaying validation messages is important because it allows developers to write reusable code that can be applied to any form control, instead of having to write separate code for each individual form control. This reduces the amount of code to be written, making the development process more efficient and scalable. A generic solution also makes it easier to maintain and update the code base, as changes can be made in a single place, rather than having to update several components.
Simple form validation
In this section, we'll look at a simple example of a form requiring validation. Let's say we have a registration form that asks users to provide their name, e-mail address and password. Without a reusable validation component, we would typically add validation to this form as follows
We start by declaring a FormGroup
using the reactive forms approach in Angular (in this example, we're using a standalone component)
In our example, we import the necessary module [ReactiveFormsModule] from @angular/forms
the creation of a FormGroup
instance with its controls. Visit FormGroup
is used to group together a set of FormControl
instances, each representing a form entry.
To create a FormControl
In this case, you pass a default value as the first argument and an array of validators as the second argument. The validators are used to validate the input value.
For example, you can use :
Validators.required
validator to make the required entryValidators.email
to validate entry as e-mail- or you can create your own custom synchronous or asynchronous validator
In the component model, you link the inputs to their respective controls using the formControlName
directive. To display error messages, you can use the ngIf
directive and access the validity of controls using the get
method FormGroup
instance.
In the model, we use Angular's built-in directives to display validation error messages according to the validation rules declared in the component's TypeScript code. The formControlName
directive is used to link the input element to a form control, while the ngIf
is used to show or hide the error message depending on the validity of the form control.
In this code, we'll look at a common problem in Angular's reactive forms, the duplication of validation logic in the model. This approach can lead to repetitive and error-prone code, so we'll explore a better way of implementing form validation in Angular.
This approach can quickly become cumbersome, especially if the form contains many fields. What's more, implementing validation in the model can complicate the management of validation rules and the display of error messages, as well as increasing the risk of errors.
Reusable component validation message
To solve the problem with classic validation, we can centralize the validation logic in a reusable component and reuse it for each form field. This approach facilitates the management of validation rules and the display of error messages, improves code maintainability and reduces the risk of errors.
we start by creating a standalone component (you can't use any standalone component) to handle form validation messages. This component takes a form control as input and displays error messages based on existing errors in the form control.
- Create a new ErrorMessage component
ng gc error messages --standalone
CREATE src /app/error-message/error-message .component .scss ( 0 bytes)
CREATE src /app/error-message/error-message .component .html ( 28 bytes)
CREATE src /app/error-message/error-message .component .spec .ts ( 637 bytes)
CREATE src /app/error-message/error-message .component .ts ( 398 bytes)
- This component requires a
AbstractControl
to manage validation
- Create a TypeScript file ( validators-utils.ts ) that includes a list of messages displayed according to error type, and a function to manage them
stringFormat
is a function that takes a string template as its first argument and a list of variable arguments. The function replaces occurrences of{x}
in the template by the corresponding argument in the list. If the argument to the specified index is not defined, the original{x}
is left in the chain.ValidationErrors: defines the error map returned by failed validation checks.
messages
is a constant Map object that associates validator names with their error messages and the validator's error key. Error messages can include placeholders in the form of{x}
will be replaced by the corresponding arguments passed tostringFormat
.
validatorErrorsKey
is a validator error table. These tables are used to extract the necessary values from thevalidatorErrors
object to be transmitted as arguments tostringFormat
.
getValidatorErrorMessage
is a function that takes two arguments,validatorName
andvalidatorErrors
. The function first retrieves the object ( {message : string,validatorErrorsKey? : string[]} ) associated with the validator's name from themessages
card.It then recovers the values of validator errors, then uses them
stringFormat
to format the error message associated with the validator name from themessages
card. If there are no parameters associated with the validator name, the function simply returns the error message.
For example, if we have a Validator.minLength(8)
and we break this rule by typing only 5 characters, then :
validatorName = minlength
validatorErrors = { 'actualLength' : 5 , 'requiredLength' : 8 }
- To integrate the exported function
getValidatorErrorMessage
in theErrorMessageComponent
function to display error messages. To do this, simply import the function into the component file, then call the function, passing it the necessary parameters such asvalidatorName
andvalidatorErrors
. The returned string can then be used as an error message.
- Now it's time to use our reusable validation component in our forms. To use our component, we need to import it and simply use it in our model.
- and in the
Now we have our reusable component and it clearly provides a clean and simple solution for form validation. It eliminates the potential for errors that are often present in traditional validation methods, making it easier for developers and maintainers to use.
Reusable component validation message with Angular Material
Now let's learn how to integrate our component with Angular Material. We'll be using MatFormFieldModule
with mat-error
to display messages. The problem mat-error
is that it must be used directly in mat-form-field.
To overcome this, we need to use our reusable component as an attribute, not as an element. This is achieved by using it as an attribute of the mat-error
.
- To use a selector as an attribute, we can use square brackets
[ ]
in the selector declaration
@Component({Composant ({
selector : '[app-error-message]' ,
standalone : true ,
imports : [CommonModule],
template : `<ng-container *ngIf= "errorMessage !== null" >{{errorMessage}}
</ ng-container>`,
}) classe
d'exportation ErrorMessageComponent
- and now we can use our component in
mat-error
(don't forget to import MatFormFieldModule and MatInputModule)
Summary
In this article, we discovered the benefits of using reusable components for form validation in Angular and how to implement it. This approach leads to more manageable code and reduces the risk of errors by reusing validation logic.
You can find the code here, I use an application based on standalone components. You can read more about it in this article.
If you have any questions or comments, please let me know in the comments below.
To learn more about Angular, JS and Java, you can follow me on Medium or Twitter.