Search code examples
angulartypescriptangular-reactive-forms

Custom validator with condition only detect changes once


I have a FormGroup look like this:

this.complaint = new FormGroup({
      date: new FormControl(null, Validators.required),
      isRangeDate: new FormControl(false, Validators.required),
      untilDate: new FormControl(null, rangeDateValidator()),
    });

and I have this custom validator rangeDateValidator

function rangeDateValidator(): ValidatorFn {
  return (control: AbstractControl): ValidationErrors | null => {
    console.log(control?.parent?.get('isRangeDate')?.value)
    return control?.parent?.get('isRangeDate')?.value ? {required: true} : null;
  }
}

that basically check if user chose to input range date and if so - it's change the untilDate control to be required. this thing is working only in the first time - isRangeDate by default is false so it's no required validation added to the control, and when it change to true it's add the required to the control, but only once - when I change it back to isRangeDate: false, the required validation still attach to it and I can see in the console that the validator function didn't call, even the FormGroup is changed.

any ideas?


Solution

  • I manage to find the answer for it in the end:

    • the reason the rangeDateValidator validator didn't fire the second time is that this validator is attached to untilDate FormControl so it only fires when the untilDate value is changed and this has not happened because the only field that changed is only the isRangeDate field, so the validator function didn't call.

    so, the answer for it is to add a custom validator on the FormGroup level (not specific on the FormControl), check out this service:

    @Injectable({
      providedIn: 'root'
    })
    export class ComplaintService {
      private readonly complaint: FormGroup;
    
      constructor() {
        this.complaint = new FormGroup({
          date: new FormControl(null, Validators.required),
          isRangeDate: new FormControl(false, Validators.required),
          untilDate: new FormControl(null),
          situationDetails: new FormControl(null, Validators.required),
          whyNotRight: new FormControl(null),
          whatYouDone: new FormControl(null),
          isTrial: new FormControl(null, Validators.required),
          howCanWeHelp: new FormControl(null),
          isAboutProperty: new FormControl(null, Validators.required),
          propertyDetails: addressForm(),
          attachments: filesForm()
        }, this.groupValidator());
      }
    
      groupValidator(): ValidatorFn {
        return (group: AbstractControl): ValidationErrors | null => {
          if (group?.get('isRangeDate')?.value) {
            group.get('untilDate')?.addValidators(Validators.required)
          } else {
            group.get('untilDate')?.removeValidators(Validators.required)
            group.get('untilDate')?.setErrors(null);
          }
    
          return group.errors;
        }
      }
    }
    

    this way the validator function groupValidator is fired every change in the FormGroup and can add or remove validators from there

    hope it helps :)