Custom Validator on Angular Reactive Form not firing

699 views Asked by At

I'm working with a dynamic reactive form that takes a json input and builds out a form. I also wrote a custom date validator to check if a date is older than another given date (the date is passed in to the validator) .. and returns an error when the input date by the user is older than the given date. Because of the way the form is built... I'm adding or removing the validator based on a user's prior selection while going through the form (to make the form valid).

This is the code block of me adding the form control and the validator.

`

var newdate = new Date();
this.dynamicForm.addControl(control.name, this.formBuilder.control(control.value, this.beforeDateValidator(newdate)));

`

And this is what the validator looks like...

`

    beforeDateValidator(dateValue: Date): ValidatorFn {
        console.log('im firing');

        return(control: AbstractControl) : ValidationErrors | null => {
            const value: Date = control.value;
            // console.log(value);
    
            if(!value) {
                return null;
            }

            if (dateValue=== null) {
                return null;
            }

            if (value < dateValue) {
                return { beforeDateValidator: 'Invalid Date' }
            } else {
                return null;
            } 
        }
    
    }

`

The issue is... the validator doesn't fire when the user selects the right values and inputs the date value that's supposed to trigger the invalid date message.

2

There are 2 answers

10
Yong Shun On BEST ANSWER

The custom validator will be triggered, but the problem is the control.value return a string value and you compare it with a Date value. Hence it leads to an unexpected value that the error is not returned which is used to assign the error to the form control.

Place a console.log() as below and you will find that it prints as string.

console.log(typeof value);

Hence make sure that you need to convert the control.value to Date type before comparing:

if (new Date(value) < dateValue) {
  ...
}

Note that your current way to add new form control and assign value with a Date, is not working correctly, the form control will not show the assigned date.

You need to format the date from ISOString to "yyyy-MM-dd" format as below:

import { formatDate } from '@angular/common';

this.dynamicForm.addControl(
  control.name,
  this.formBuilder.control('', this.beforeDateValidator(newdate))
);

this.dynamicForm.controls[control.name].patchValue(
  formatDate(control.value, 'yyyy-MM-dd', 'en')
);

Demo @ StackBlitz

1
paranaaan On

Seem like you try to create new FormControl with the same name that already exist this.dynamicForm.addControl(control.name .....

Solution 1 You may change to use addValidator to the remain control instead of create new one.

this.form.controls["dynamicForm"].addValidators([this.beforeDateValidator(newdate)]);

Solution 2 Create new one with the name that not exist.

.ts

Object.keys(this.dynamicForm.controls).forEach((control) => {
  this.dynamicForm.addControl(
    control + 'a',
    formBuilder.control('', [this.beforeDateValidator(newdate)])
  );
});

.html - ensure formControlName contain the right name as well.

<form [formGroup]="dynamicForm" (ngSubmit)="onSubmit()">
  <label for="first-name">First Name: </label>
  <input id="first-name" type="text" formControlName="control1a" />

  <label for="last-name">Last Name: </label>
  <input id="last-name" type="text" formControlName="control2a" />

  <button type="submit">Submit</button>
</form>

example: Stackblitz