Why should I use Validators.compose()?
Asked Answered
C

2

55

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()?

Calvert answered 22/2, 2017 at 14:59 Comment(5)
I guess it's mostly there fore historical reasons.Heterodyne
Hehe, I guess... It's really weird that I found that historic method everywhere so far (videos, blogs...), and then suddenly on Angular Cookbook I found out I don't need it.Calvert
There was a big rework of the Forms module in July/August 2016, and there the requirement of compose() was removed, but I guess they kept it to not unnecessarily break existing code and confuse users.Heterodyne
Oh, I've figured it would probably be something like that. Well thanks for the info. :)Calvert
Well... it's still necessary to add multiple validators on FormArray (because its constructor only accepts a single ValidatorFn instead of array. It won't be necessary only when they merge this pull request.Dennett
G
27

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.

Genny answered 3/10, 2018 at 10:58 Comment(1)
Hey. What does fns means? Sorry. I did'nt get this abbreviation meaning.Cavernous
G
25

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.

Garnett answered 14/5, 2020 at 19:16 Comment(3)
Why not just reuse an array throughout the codebase? I see no reason to use the Validators.compose.Itu
That was my first tought as well - just use array.Hargeisa
I'd just go with arrays and spread operator since it shows clearly whats going on, without navigation back and forth or consulting the docs of another function.Canvasback

© 2022 - 2024 — McMap. All rights reserved.