2

I am looking to remove the specific validator from validator array in order to set the controls again when some values changed.

I know normal solution where I need to set validators again and again.

checked(event: MatCheckboxClickAction): void {
    const control = (this.form.get(
        'information',
    ) as FormGroup).controls.data1;
    if (event) {
        this.updateRequiredValidator(control);
    } else {
        control.setValidators([
            Validators.maxLength(9), Validators.minLength(2)
        ]);
        control.updateValueAndValidity();
    }
}

updateRequiredValidator(control: AbstractControl): void {
    control.setValidators([
        Validators.required,
        ...(control?.validator ? [control?.validator as ValidatorFn] : []),
    ]);
    control.updateValueAndValidity();
}

I would like to just removed the Validators.required on else part instead of setting validators again and again.

app
  • 197
  • 8
  • 24

2 Answers2

3

I think that the best bet is use a "customValidator" like "requireIf".

  requiredIf(field: string) {
    return (control: FormControl):{required:boolean}|null => {
      const form = control.parent as FormGroup;
      const check=form?form.get(field):null
      if (form && check && check.value)
        return !control.value ? { required: true } : null;

      return null;
    };
  }
//e.g.
this.form=new FormGroup({
   check:new FormControl();
   data1:new FormControl(null,this.requiredIf('check'))
})

But be carefull, when check change you need use

this.form.get('data1').updateValueAndValidity()

in the stackblitz I use mat-angular and use the (change) to make the updateValueAndValidity

UPDATE to defined the typedef of the function

requiredIf(field: string):ValidatorFn {
    return (control: AbstractControl):{required:boolean}|null => {
      ....
    }
}
Eliseo
  • 50,109
  • 4
  • 29
  • 67
  • just a small question.. How it can work for nested groups? – app Nov 26 '20 at 00:07
  • form = new FormGroup({ check: new FormControl(true), val: new FormGroup({ check: new FormControl(true), }), data1: new FormControl(null, [ this.requiredIf("val.check"), Validators.maxLength(10) ]) }); – app Nov 26 '20 at 00:07
  • Type '(control: FormControl) => { required: boolean;} | null' is not assignable to type 'ValidatorFn'. Types of parameters 'control' and 'control' are incompatible. I do get following error in the stackblitz. – a.p. patel Nov 26 '20 at 00:13
  • 1
    app, If is in a nested group you need "get" the form, you should use parent.parent, e.g. if your formgroup is `{form:{check,{some:data1}}`, and you can use in get the dot notation, e.g. `form('subgroup.check')`. If you get an error in your validator, use `AbstractControl` instead FormControl – Eliseo Nov 26 '20 at 08:47
  • thanks a lot.. just quick question.. what is return type of this function as I am following typedef for all methods. – app Nov 26 '20 at 14:37
  • Thanks a lot for helping out.Is that work for multi field? I was trying to expand the logic to work if 2 checkbox are selected then only make that required. – app Nov 26 '20 at 16:47
  • 1
    the logic is the same, you need "get" the two checkbox (first find the formgroup, then the two checkbox using get()) – Eliseo Nov 26 '20 at 16:58
1

Instead of adding and removing the validators, you can create the custom validator function that can check all possible error and set error using setError method of AbscractControl

Amit Desai
  • 424
  • 3
  • 8