Learn how to create a custom validator with parameters in Angular Reactive Forms. This is the continuation of our previous tutorial, where we learned how to build a custom validator in Reactive forms.
Table of Contents
Custom Validator with Parameter
Here is the code of greater than validator (gte
) from the Custom Validators in Angular Reactive Form tutorial. The validator checks if the given value is greater than 10 and if not return ValidationErrors
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | export function gte(control: AbstractControl): ValidationErrors | null { const v:number=+control.value; if (isNaN(v)) { return { 'gte': true, 'requiredValue': 10 } } if (v <= 10) { return { 'gte': true, 'requiredValue': 10 } } return null } |
The problem with the above validator is that the value 10 is hardcoded. Hence, we will be not able to reuse it. If we want to resue it, we need to pass the number as the parameter.
Let us add the parameter val:number
to the validator as shown below.
1 2 3 | export function gte(control: AbstractControl,val:number): ValidationErrors | null { |
The compiler immediately throws an error as shown below.
1 2 3 | error TS2345: Argument of type '((control: AbstractControl, val: number) => ValidationErrors)[]' is not assignable to parameter of type 'ValidatorFn | ValidatorFn[] | AbstractControlOptions'. |
That is because, the Validator
must implement ValidatorFn Interface. It can have only one parameter i.e control: AbstractControl
1 2 3 4 5 | interface ValidatorFn { (control: AbstractControl): ValidationErrors | null } |
Passing Parameters to a Custom Validator
To pass a parameter, we need to create a factory function or a function that returns a function. The example code is as shown below
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | export function gte(val: number): ValidatorFn { return (control: AbstractControl): ValidationErrors | null => { let v: number = +control.value; if (isNaN(v)) { return { 'gte': true, 'requiredValue': val } } if (v <= +val) { return { 'gte': true, 'requiredValue': val } } return null; } } |
First, we create a factory function. It receives the val
as the argument. It must return the function of the type ValidatorFn
1 2 3 | export function gte(val: number): ValidatorFn { |
The get
must return a function ValidatorFn
1 2 3 4 5 | return (control: AbstractControl): ValidationErrors | null => { //Validaton code here } |
Using the Validator
Now, add the validator to the Validator collection of the FormControl as shown below
1 2 3 4 5 | myForm = new FormGroup({ numVal: new FormControl('', [gte(10)]), }) |
Accessing the Errors in Template
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <h1>Custom Validator with Parameter in Angular</h1> <h2>Reactive Form</h2> <form [formGroup]="myForm" (ngSubmit)="onSubmit()" novalidate> <div> <label for="numVal">Number :</label> <input type="text" id="numVal" name="numVal" formControlName="numVal"> <div *ngIf="!numVal.valid && (numVal.dirty ||numVal.touched)"> <div *ngIf="numVal.errors.gte"> The number should be greater than {{numVal.errors.requiredValue}} </div> </div> </div> <p>Is Form Valid : {{myForm.valid}} </p> <p> <button type="submit" [disabled]="!myForm.valid">Submit</button> </p> </form> |
Summary
We learned how to pass a parameter to a custom validator. First, we create a factory function, which accepts the parameter. The factory function returns the validator function. Using this technique we can pass as many as parameters to a custom validator in Angular.
the best solution that i have ever been looking for. Thank you for this! 🙂