the below code works,
https://stackblitz.com/edit/stackblitz-starters-wnququ?file=src%2Fmain.html
But I need to take it a step further and ensure that the end date of the FormGroup at index (x) is not greater than or equal to the start date of FormGroup at index (x + 1) - (all inside the main form array).
Do you know how I do that?
This is what I have so far (refer to Stackblitz demo too)
Validators
Currently, my date validator looks like:
// VALIDATORS
public startDateAfterEndDateMatcher: ValidatorFn =
this.dateComparisonValidator(
'startDate',
'endDate',
'startDateAfterEndDate',
(date1: Date, date2: Date) => date1 && date2 && date1 > date2
);
private dateComparisonValidator(
fieldName1: string,
fieldName2: string,
errorName: string,
condition: (value1: any, value2: any) => boolean
): ValidatorFn {
return (control: AbstractControl): ValidationErrors | null => {
const field1Value = control.get(fieldName1)?.value;
const field2Value = control.get(fieldName2)?.value;
console.log('condition', condition(field1Value, field2Value));
if (condition(field1Value, field2Value)) {
const errors: ValidationErrors = {};
errors[errorName] = true;
return errors;
}
return null;
};
}
Form Structure
The form structure currently looks like this. The form validator gets added on to each formGroup object, (but I'd like to try and validate across formGroups now - which I'm not sure how to do)
private initFormGroup() {
this.datesInfo = this.formBuilder.group({
datesArray: this.formBuilder.array(
(this.datesArray || []).map((_) =>
this.formBuilder.group(
{
startDate: [
'',
{
nonNullable: true,
validators: [Validators.required],
},
],
endDate: [
'',
{
validators: [],
},
],
},
{ validators: [this.startDateAfterEndDateMatcher] }
)
)
),
});
}
Error State Matcher
My error state matcher (that attaches to each form group in the form array) looks like:
// ERROR MATCHER
export class SingleErrorStateMatcher implements ErrorStateMatcher {
private errorCode: string;
public constructor(errorCode: string, private formGroup?: FormGroup) {
this.errorCode = errorCode;
}
isErrorState(
control: FormControl | null,
formGroup: FormGroupDirective | NgForm | null
): boolean {
let parentFormGroup = this.formGroup ?? formGroup;
console.log('parentFormGroup', parentFormGroup);
return (
!!(parentFormGroup?.dirty || parentFormGroup?.touched) &&
!!(parentFormGroup?.invalid && parentFormGroup?.hasError(this.errorCode))
);
}
}
Initialisation
These get pushed inside ngOnInit only (so it's not fully dynamic in the sense, I haven't yet thought about what happens, if I want to add another pair of dates- or if I delete/roll back a pair of dates... - but that's ok for now)
// create error state matchers
for (let i = 0; i < this.datesArray.length; i++) {
this.startDateAfterEndDateMatchers.push(
new SingleErrorStateMatcher(
'startDateAfterEndDate',
this.datesInfo.controls['datesArray'].get(`${i}`) as FormGroup
)
);
}