140

We have a component that has a dynamically built form. The code to add a control with validators might look like this:

var c = new FormControl('', Validators.required);

But let's say that I want to add 2nd Validator later. How can we accomplish this? We cannot find any documentation on this online. I did find though in the form controls there is setValidators

this.form.controls["firstName"].setValidators 

but it is not clear how to add a new or custom validator.

luiscla27
  • 4,956
  • 37
  • 49
melegant
  • 1,649
  • 2
  • 12
  • 15

8 Answers8

189

You simply pass the FormControl an array of validators.

Here's an example showing how you can add validators to an existing FormControl:

this.form.controls["firstName"].setValidators([Validators.minLength(1), Validators.maxLength(30)]);

Note, this will reset any existing validators you added when you created the FormControl.

Angular 12 update

Since Angular 12, if you want to add new validators to the form without removing the existing validators, you can use addValidator:

this.form.controls["firstName"].addValidators([Validators.minLength(1), Validators.maxLength(30)]);
luiscla27
  • 4,956
  • 37
  • 49
Andy-Delosdos
  • 3,560
  • 1
  • 12
  • 25
  • 7
    ha...sometimes you look at something so long it is best to just step away. THANK YOU!! – melegant Aug 06 '16 at 14:43
  • This really solved the problem that I was trying to fix for a long time. Thanks a ton for sharing! – Devner May 12 '17 at 05:28
  • 2
    Is there a way to remove validation – Abhijith s.s Aug 18 '17 at 11:57
  • Cheers. If you have css in the field use `.patchValue()` after so the the styling refresh. – Swoox Nov 24 '17 at 12:24
  • dude it is like a hack, consider a scenario where there are 50 fields or more generated from xsd sent from server which has basic validators like max length or min length and then there are dynamic mandatory fields based on user then i can't get existing validtors or push to existing validators. – bharath muppa May 11 '18 at 14:42
  • 9
    any way to do this without overriding the old ones? or any way to append the new ones? – danday74 Oct 15 '18 at 10:45
  • 1
    @danday74, check out Eduard Void's answer at the bottom of this question. Should be accepted answer imo. He explains how to do what you need to know, which I also needed to know how to do. – Chris Nov 16 '18 at 20:47
  • Note that this will clear all existing validators that may have been set during form initialization. – Alvin Saldanha Dec 10 '19 at 23:16
  • 32
    I had to also call `.updateValueAndValidity()` on the form control after setting the new validators. – Keeleon Jan 09 '20 at 16:02
  • Explains how to wipe and reset validators, not add validators – RoboticRenaissance Sep 29 '20 at 15:37
  • addValidators() was added in v12.2.0 https://github.com/angular/angular/blob/master/CHANGELOG.md#1220-rc0-2021-07-28 – Iván Sainz Sep 15 '21 at 10:21
137

To add onto what @Delosdos has posted.

Set a validator for a control in the FormGroup: this.myForm.controls['controlName'].setValidators([Validators.required])

Remove the validator from the control in the FormGroup: this.myForm.controls['controlName'].clearValidators()

Update the FormGroup once you have run either of the above lines. this.myForm.controls['controlName'].updateValueAndValidity()

This is an amazing way to programmatically set your form validation.

shammelburg
  • 6,974
  • 7
  • 26
  • 34
  • 4
    For me it worked without the last line, I'm pretty sure new versions of Angular update the form validity by themselves now. But thanks for telling us about the `updateValueAndValidity` method, might come handy one day! – Nino Filiu Jul 24 '18 at 09:06
  • @NinoFiliu `updateValueAndValidity` is still used to perform the validation, and isn't handled any differently in newer versions of Angular. What happens is `setValidators` updates the validators, but doesn't run a validation check, and then you use `updateValueAndValidity` to perform the validation. You must be setting the validators at a point where change detection handles it for you, but you'll find using `updateValueAndValidity` on the group or control depending what validator you just set crucial - https://github.com/angular/angular/issues/19622#issuecomment-341547884. – mtpultz Aug 09 '18 at 19:44
  • 5
    I'm on Angular 6 and couldn't make it work without the `updateValueAndValidity`. Thanks @shammelburg ! – Oli Crt Dec 20 '18 at 16:12
  • 1
    On Angular 7 and it also wouldn't work for me without the last update line. – David Findlay Jun 19 '19 at 22:56
  • Yes. It is working without `updateValueAndValidity()`, but in some cases, it does not. if you added `updateValueAndValidity()` after `setValidators()` It will **immediately affect the changes related to control**. So it is better to add updateValueAndValidity()`. – Jamith NImantha Jan 27 '20 at 10:30
  • In my case, it worked only when I **removed** `updateValueAndValidity()`. – Brozorec Feb 11 '20 at 13:53
  • First I put all this in `AfterViewInit`, which did not work. Then I put the logic in `OnInit`, then it worked. – Mike de Klerk Jun 18 '20 at 18:57
  • Explains how to wipe and reset validators, not add validators – RoboticRenaissance Sep 29 '20 at 15:37
117

If you are using reactiveFormModule and have formGroup defined like this:

public exampleForm = new FormGroup({
        name: new FormControl('Test name', [Validators.required, Validators.minLength(3)]),
        email: new FormControl('test@example.com', [Validators.required, Validators.maxLength(50)]),
        age: new FormControl(45, [Validators.min(18), Validators.max(65)])
});

than you are able to add a new validator (and keep old ones) to FormControl with this approach:

this.exampleForm.get('age').setValidators([
        Validators.pattern('^[0-9]*$'),
        this.exampleForm.get('age').validator
]);
this.exampleForm.get('email').setValidators([
        Validators.email,
        this.exampleForm.get('email').validator
]);

FormControl.validator returns a compose validator containing all previously defined validators.

Eduard Void
  • 2,646
  • 1
  • 13
  • 13
  • 21
    Imo this should be the accepted answer. It demonstrates how to add validators like OP requested, but also shows you how to retain previously set validators; which was the first thing I googled how to do after I read the accepted answer, because I didn't want to overwrite some validators I already had, but still needed to programatically add additional ones. Thank you for this answer @Eduard Void – Chris Nov 16 '18 at 20:45
  • 4
    I agree with my predecessor. The question was how to **add** new validator to control form, not how to **replace** it. – Plusce Dec 05 '18 at 14:57
  • 10
    I did `control.setValidators(control.validator ? [ control.validator, Validators.email ] : Validators.email);` to get around strict null checks – Wilhelmina Lohan Aug 21 '19 at 20:25
7

In addition to Eduard Void answer here's the addValidators method:

declare module '@angular/forms' {
  interface FormControl {
    addValidators(validators: ValidatorFn[]): void;
  }
}

FormControl.prototype.addValidators = function(this: FormControl, validators: ValidatorFn[]) {
  if (!validators || !validators.length) {
    return;
  }

  const old_validator = this.validator;

  this.clearValidators();
  this.setValidators( old_validator ? [ old_validator , ...validators ] : validators );
};

Using it you can set validators dynamically:

some_form_control.addValidators([ first_validator, second_validator ]);
some_form_control.addValidators([ third_validator ]);
lucifer63
  • 784
  • 9
  • 32
  • This is very good solution for Angular 12 prior version but *this.clearValidators();* will remove the existing validators and add new passed validator. – Shivek Parmar Apr 15 '23 at 23:05
6

If you need to remove some existing validation on the added form control then call below function on the control

this.form.controls["name"].clearValidators();

After that you need to call below function to update the form controls and it will be effective immediately on the form controls.

this.form.controls['name'].updateValueAndValidity();

If you need to add some validation on the already added form control then call the below function on the control

this.signupForm.controls['name'].setValidators([Validators.required]);

After that call updateValueAndValidity() function immediately, so it can be reflected instantly.

5

I think the selected answer is not correct, as the original question is "how to add a new validator after create the formControl".

As far as I know, that's not possible. The only thing you can do, is create the array of validators dynamicaly.

But what we miss is to have a function addValidator() to not override the validators already added to the formControl. If anybody has an answer for that requirement, would be nice to be posted here.

halfer
  • 19,824
  • 17
  • 99
  • 186
user2992476
  • 1,536
  • 2
  • 17
  • 29
0

A simple solution would be to first get all the validators in the form control and assign a new validatorFn to it when needed code will go like this.

//get existing validators and assign a new validator

const formControl = this.form.controls["firstName"];

 const validators: ValidatorFn[] = !!formControl.validator ?
  [formControl.validator, Validators.required] :
  [Validators.required];

formControl.setValidators(validators);

formControl.validtor holds the existing validators (not asyncValidators) we check if it's not null using ternary and add to it ( here we add the required validator to it), otherwise, we just assign our new validator

darkel
  • 31
  • 2
0

Updating validators based on other Form Control's values.

First setting the form:

  form: FormGroup = new FormGroup({
    firstName: new FormControl<string>(null),
    lastName: new FormControl<string>(null),
  });

then on init:

  ngOnInit(): void {
    this.form.get('firstName').valueChanges.subscribe((value) => {
      if (value) {
        this.form.get('lastName').setValidators(Validators.nullValidator);
      } else {
        this.form.get('lastName').setValidators(Validators.required);
      }
      this.form.get('lastName').updateValueAndValidity({ emitEvent: false });
    });
    this.form.get('lastName').valueChanges.subscribe((value) => {
      if (value) {
        this.form.get('firstName').setValidators(Validators.nullValidator);
      } else {
        this.form.get('firstName').setValidators(Validators.required);
      }
      this.form.get('firstName').updateValueAndValidity({ emitEvent: false });
    });
  }

It's important to add { emitEvent: false } so you don't get the Maximum call stack size exceeded error

Bullsized
  • 362
  • 4
  • 7