I have a field I want to validate with multiple validators.
Using the Module Driven approach the code looks likes this:
this.exampleForm = this.fb.group({ date_start : [ '', Validators.compose([ Validators.required, Validators.pattern("[0-9]{2}-[0-9]{2}-[0-9]{4}") ])] })
But I can also write this withouth Validators.compose() like:
this.exampleForm = this.fb.group({ date_start : [ '', [ Validators.required, Validators.pattern("[0-9]{2}-[0-9]{2}-[0-9]{4}") ] ] })
And it works just fine. Personally I prefer the 2nd version (without compose), less code and better readability. And this begs the question, why should I use Validators.compose()?
A validator is a function that processes a FormControl or collection of controls and returns an error map or null. A null map means that validation has passed.
FormBuilder allows us to explicitly declare forms in our components. This allows us to also explicitly list each form control's validators. In our example we are going to build a small form with three inputs, user name, email and profile description. We will start with looking at our app.
Angular uses directives to match these attributes with validator functions in the framework. Every time the value of a form control changes, Angular runs validation and generates either a list of validation errors that results in an INVALID status, or null, which results in a VALID status.
We can add Validators dynamically using the SetValidators or SetAsyncValidators. This method is available to FormControl, FormGroup & FormArray. There are many use cases where it is required to add/remove validators dynamically to a FormControl or FormGroup.
When we create new FormControl/FormGroup/FormArray
(AbstractControl) - coerceToValidator
is called.
function coerceToValidator( validatorOrOpts?: ValidatorFn | ValidatorFn[] | AbstractControlOptions | null): ValidatorFn| null { const validator = (isOptionsObj(validatorOrOpts) ? (validatorOrOpts as AbstractControlOptions).validators : validatorOrOpts) as ValidatorFn | ValidatorFn[] | null; return Array.isArray(validator) ? composeValidators(validator) : validator || null; } export function composeValidators(validators: Array<Validator|Function>): ValidatorFn|null { return validators != null ? Validators.compose(validators.map(normalizeValidator)) : null; }
So there is no need to compose validators before we pass it to an AbstractControl.
6/13/16 was added feat(forms): compose validator fns automatically if arrays
from now on, Validators.compose is there for backward compatibility.
I know this is an old-ish question, but it came up on a recent search.
The main reason you may want to use Validators.compose()
is to reuse multiple validators. Let's say you want to check that a value is between 0 and 100. The first time, you would write:
this.form = this.fb.group({ foo: [ 0, [ Validators.min(0), Validators.max(100)]] });
Now let's say you want to do that in several places within your app. To avoid code duplication, you would create your own validator by simply composing it from the existing validators, expose it and reuse it everywhere you need:
// custom-validators.ts import { Validators } from '@angular/forms'; export class CustomValidators { readonly betweenZeroHundred = Validators.compose([ Validators.min(0), Validators.max(100), ]); } // form1 this.form = this.fb.group({ foo: [ 0, [CustomValidators.betweenZeroHundred()]] }); // form2 this.form = this.fb.group({ bar: [ 100, [CustomValidators.betweenZeroHundred()]] });
Nowadays, with the spread operator, you can achieve a similar result, without the compose()
:
export class CustomValidators { readonly betweenZeroHundred = [Validators.min(0), Validators.max(100)]; } this.form = this.fb.group({ bar: [ 100, [...CustomValidators.betweenZeroHundred, Validators.required]] });
In the end, it's a matter of which approach is a better fit for your team and your situation.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With