Home > other >  Angular - Conditional validator is not working
Angular - Conditional validator is not working

Time:01-27

I have an Angular form where the following validation should happen:

  1. checkbox === ticked then validate the input else no validation

  2. checkbox === unticked then no validation but rechecking should enable the validation

I am having issues when on the page load the checkbox is unticked and the input box does not have any value the validation doesn't trigger which is expected. However, the input box validation doesn't trigger immediately after clicking the checkbox when the input is empty.

Here is the code:

private myFormValidator(predicate: Function, validator: ValidatorFn): ValidatorFn {
        return ((formControl: FormControl) => {
            if (!formControl.parent) {
                return null;
            }
            let error = null;
            if (predicate()) {
                console.log('predicate()');
                return validator(formControl);
            }
            return null;

        });
    }


 this.partnerInvoiceDetailsForm = this.fb.group(
            {

                rebates: new FormGroup({
                    territories: new FormGroup({
                        rebateTier: new FormControl(null, [
                            this.myFormValidator(() => this.rebateActive(this.rebateIdMap[1]).value, Validators.required)]),
                        rebateValue: new FormControl(null),
                        rebateActive: new FormControl(null)
                    })
                   }
        );

        // console.log(this.partnerInvoiceDetailsForm.get('rebates.territories.rebateTier'));
        this.partnerInvoiceDetailsForm.get('rebates.territories.rebateActive')
            .valueChanges
            .subscribe(value => {
                console.log(value)
                this.partnerInvoiceDetailsForm.get('rebates.territories.rebateTier').updateValueAndValidity();
            });

CodePudding user response:

Approach 1: With valueChanges observable

During the "rebates.territories.rebateActive" value change event, you can add the validator programmatically via addValidators and removeValidators methods. Note that you have to pass the same reference for the validator function added into validators in order to remove it correctly.

const myFormValidator = this.myFormValidator(
  () => this.rebateActive(this.rebateIdMap[1]).value,
  Validators.required
);

this.partnerInvoiceDetailsForm
  .get('rebates.territories.rebateActive')
  .valueChanges.subscribe((value) => {
    console.log(value);

    if (value)
      this.partnerInvoiceDetailsForm
        .get('rebates.territories.rebateTier')
        .addValidators(myFormValidator);
    else
      this.partnerInvoiceDetailsForm
        .get('rebates.territories.rebateTier')
        .removeValidators(myFormValidator);

    this.partnerInvoiceDetailsForm
      .get('rebates.territories.rebateTier')
      .updateValueAndValidity();
  });

Demo Approach 1 @ StackBlitz


Approach 2: Modify myFormValidator ValidatorFn by adding dependency parameter.

If you allow to modify the myFormValidator, you can add dependency parameter and implement the logic to check the value of dependency to proceed/exit the logic.

private myFormValidator(
  predicate: Function,
  dependency: string,
  validator: ValidatorFn
): ValidatorFn {
  return (formControl: FormControl) => {
    if (!formControl.parent) {
      return null;
    }

    if (!formControl.parent.get(dependency)?.value) return null;

    let error = null;
    if (predicate()) {
      console.log('predicate()');
      return validator(formControl);
    }
    return null;
  };
}

The key point of implementing this approach is you have to trigger this.partnerInvoiceDetailsForm.get('rebates.territories.rebateTier').updateValueAndValidity() when the rebates.territories.rebateActive's value is changed.

ngOnInit() {
  this.partnerInvoiceDetailsForm = this.fb.group({
    rebates: new FormGroup({
      territories: new FormGroup({
        rebateTier: new FormControl(null, [
          this.myFormValidator(
            () => this.rebateActive(this.rebateIdMap[1]).value,
            'rebateActive',
            Validators.required
          ),
        ]),
        rebateValue: new FormControl(null),
        rebateActive: new FormControl(null),
      }),
    }),
  });

  this.partnerInvoiceDetailsForm
    .get('rebates.territories.rebateActive')
    .valueChanges.subscribe((value) => {
      console.log(value);

      this.partnerInvoiceDetailsForm
        .get('rebates.territories.rebateTier')
        .updateValueAndValidity();
    });
}

Demo Approach 2 @ StackBlitz

  • Related