88
votes

In angular2 I want to trigger Validators for some controls when a another control is changed. Is there some way that I can just tell the form to re-validate? Better still, can I request validation of specific fields?

Example: Given Checkbox X and input P. Input P has a validator that behaves differently based on the model value of X. When X is checked/unchecked I need to invoke the validator on P. The Validator on P will look at the model to determine the state of X and will validate P accordingly.

Here's some code:

constructor(builder: FormBuilder) {
    this.formData = { num: '', checkbox: false };

    this.formGp = builder.group({
        numberFld: [this.formData.num, myValidators.numericRange],
        checkboxFld: [this.formData.checkbox],
    });
}

this.formGp.controls['checkboxFld'].valueChanges.observer({
    next: (value) => {
        // I want to be able to do something like the following line:
        this.formGp.controls['numberFld'].validator(this.formGp.controls['numberFld']);
    }
});

Anybody have a solution? Thanks!

7
Are you just trying to enable/disable the validation based on the value of X? What sort of validators are you using? You can cause validators to execute based on a condition in your scope, but I'm not sure if that approach will work for you. See: stackoverflow.com/questions/21370006/…stephen.vakil
@stephen.vakil - I'm using angular2.Bonneville
@Bonneville could you please explain how you are passing the checkbox state to the validator function?Varun Mulloli

7 Answers

84
votes

I don't know if you are still looking for an answer, so here is my suggestions:

Have a look at this: Angular 2 - AbstractControl

I think what you could do is following:

this.formGp.controls['checkboxFld'].valueChanges.observer({
    next: (value) => {
       this.formGp.controls['numberFld'].updateValueAndValidity();
    }
});

This should trigger and run the validators. Furthermore the state gets updated as well. Now you should be able to consult the checkbox value within your validator logic.

Hope this helps!

EDIT: Updated link and example. Code changed while I was writing my answer.

EDIT_2: alpha.48 changes the EventEmitter.observer to EventEmitter.subscribe!

EDIT_3: Changed link to the actual implementation, added link to the documents

Validaton-Guide

FormControl Documentation

48
votes

with my ControlGroup I do this because I have errors divs checking if touched

for (var i in this.form.controls) {
  this.form.controls[i].markAsTouched();
}

(this.form is my ControlGroup)

23
votes

With the help of this blog

blog link

I have came across a solution with the combine of Nightking answer

Object.keys(this.orderForm.controls).forEach(field => {
       const control = this.orderForm.get(field);
       control.updateValueAndValidity();

});

this.orderForm is the form group

14
votes

This did the trick for me

this.myForm.markAllAsTouched();
6
votes

There are more elegant ways of modeling this behavior - for example, putting your state into a ReplaySubject and observing that, and then using async validators observing the state - but the pseudo-coded approach below should work. You simply observe the value changes in the checkbox, update the model as appropriate, then force a re-validation of the numberFld with the updateValueAndValidity cal.

constructor(builder: FormBuilder) {
  this.formData = { num: '', checkbox: false };
  const numberFld = builder.control(this.formData.num, myValidators.numericRange);

  const checkbox = builder.control(this.formData.checkbox);
  checkbox.valueChanges.map(mapToBoolean).subscribe((bool) => {
    this.formData.checked = bool;
    numberFld.updateValueAndValidity(); //triggers numberFld validation
  });

  this.formGp = builder.group({
      numberFld: numberFld,
      checkboxFld: checkbox
  });
}
2
votes

You can trigger validation in this way:

this.myform.get('myfield').updateValueAndValidity();
0
votes
static minMaxRange(min: number, max: number): ValidatorFn {
    return (control: AbstractControl): ValidationErrors | null => {
        if (Validators.min(min)(control)) { // if min not valid
            return Validators.min(min)(control);
        } else {
            return Validators.max(max)(control);
        }
    };
}