1

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?

Eli Porush
  • 1,339
  • 1
  • 7
  • 18

3 Answers3

2

It does not call you're custom validator because you are changing the isRangeDate form and not the untilDate form, you only assign the custom validator to the untilDate form. Maybe you can call a function after changing the isRangeDate form with: myForm.markAllAsTouched() or myForm.valid(). I think this should revalidate the form and call the custom validator.

  • A small addition to this: instead of forcing change detection on the whole form when `isRangeDate` is modified, you can simply call `this.complaint.get('untilDate').updateValueAndValidity()` to trigger the validity check of the `untilDate` control. – ardentia Jan 20 '22 at 10:02
  • thanks for the good answer! I solve it in other way but is actually same idea - I add custom validator to the entire group instead of the control. – Eli Porush Jan 20 '22 at 10:23
  • @ardentia thanks for the addition. Didn't thought of that, even in my code :) nice, glad to hear. keep up – Doktor Gauß Jan 20 '22 at 10:31
0

I think it is because when you manually add false in input box it is taken as a string rather than boolean, so maybe that's why the validation object isn't added to untilDate again.

0

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 :)

Eli Porush
  • 1,339
  • 1
  • 7
  • 18
  • 1
    Another approach can be simply use Validators.required to the untilDate formControl. Then only disable/enable the formControl according the value of isRangeDate. Rememeber that a formControl [disabled](https://angular.io/api/forms/FormControlStatus) is not invalid. NOTE: Really it's not a good idea remove and add validators if it's not necessary. – Eliseo Jun 20 '23 at 09:21
  • ok. This is a good solution, but in this one, I'll need to `subscribe` to `isRangeDate` formControll which is less nice. – Eli Porush Jun 20 '23 at 09:51
  • Or you can use a directive like this [SO](https://stackoverflow.com/questions/47937639/how-to-make-a-disabled-reactive-form-editable-in-angular2) – Eliseo Jun 20 '23 at 10:35
  • great, thanks @Eliseo – Eli Porush Jun 20 '23 at 11:04