0

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.

shine-dev
  • 9
  • 4

2 Answers2

0

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

paranaaan
  • 1,626
  • 2
  • 9
  • 17
  • I dont think so... I checked the formcontrol and it's created properly. I dont know why... but I made some changes to your example and it doesn't fire when the type of the input is date. https://stackblitz.com/edit/angular-qzbu4u-mb3fcr?file=src/app/hero-form/hero-form.component.html – shine-dev Nov 28 '22 at 04:58
0

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

Yong Shun
  • 35,286
  • 4
  • 24
  • 46
  • Thanks.. but i don't know if this solves the problem. I've been just logging a string to the console everytime i click on the datepicker and i'm getting nothing. I can see the validator in the rawvalidators property of the control itself.. but after page load.. for some ereason, it doesn't fire when I click on the datepicker and select a date. – shine-dev Nov 28 '22 at 16:25
  • I think another thing i should mention is that... this form element doesn't show up until the user selects something earlier in the form. Does that make a difference on how the validator fires or not ? – shine-dev Nov 28 '22 at 19:03
  • Yup.. I did some testing and it turns out if i render the datepicker when the form loads.. it's all fine. but if some other event triggers the datepicker to show... then the validator doesn't work properly. – shine-dev Nov 28 '22 at 19:12
  • I think will be great if you can create a minimal, reproducible example in StackBlitz. So we can know the actual code from yours and perform the debugging. Thanks. – Yong Shun Nov 28 '22 at 23:23
  • ugh lol... so I created a stackblitz of the rest of my code and stripped out most of the stuff.. and it worked like your response. The issue was somewhere else in the code the validator was being removed and i missed it :/ ... thanks for the pointer! – shine-dev Nov 29 '22 at 06:59
  • https://stackblitz.com/edit/angular-empty-project-uuimqq?file=app/app.component.ts Check out this stackblitz. The issue i'm having is... I can't transfer the value of the date i wanna compare to the validator.. and the validator doesn't fire when I change the date previous date. It only fires when I change the date that needs to be compared to the previous date. To get the dates to show... click any of the checkboxes. – shine-dev Nov 29 '22 at 16:42
  • The problem is that your current way to set the validator to `afterdate` control with the first time value of `beforedate`. Thus the `afterdate` validator is not working correctly when `beforedate` is changed. From my [Demo[(https://stackblitz.com/edit/angular-empty-project-ch1spf?file=app/app.component.ts), what I did is subscribing the `afterdate` control's valueChanges, and reassign the validator based on current selected `beforedate` value. I think this is one of the ways to meet your requirement. While also fixed your existing code that will get error for missing `beforedate` control. – Yong Shun Nov 30 '22 at 01:53
  • This is good progress! Thanks. The only issue is... it's only triggered when you set the before date first and then set the after date next. If you set the after date first... and then change the before date to occur in the future... it won't trigger the custom validator. Perhaps we subscribe to the before date as well? – shine-dev Nov 30 '22 at 17:02
  • Yes, depends on your use case actually. If as what you want, then you need to subscribe the valueChange event for `beforedate` control, and update (reset) the validator by passing the current selected `beforedate` value. – Yong Shun Nov 30 '22 at 23:50
  • After I subscribe to the beforedate... do I update the validator ?? or do I just call it ?? .. I also dont wanna call it with the new value because it uses the control value of the before date... instead of the control date of the "after date". It's either that or write two different validators.. for an "after date invalid date" and "before date validator" – shine-dev Dec 02 '22 at 02:39