Angular 表单组上的自定义交叉字段验证未按日期字段的预期工作
Angular Custom Cross Field validation on the Form Group not working as expected for date field
我有一个包含开始日期和结束日期的表格。开始日期应为第二天,结束日期应至少为开始日期后 7 天。我正在使用 Angular material datepicker 并为这两个字段设置 minDate 值。我在 FormGroup 级别有一个自定义验证器,它验证 7 天逻辑并在验证失败时显示结束日期字段的错误消息。
验证工作正常,如果我手动输入较早的结束日期,则会显示一条错误消息。但是,如果我将开始日期更改为未来日期,然后将 select 更改为结束日期以致验证失败,则不会显示错误消息。基本上只有日期早于最初设置的 minDate 值时才会显示错误消息。对于结束日期大于最小日期的任何验证失败,不会显示错误。
我的HTML代码-
<form [formGroup]="dateForm" >
<mat-form-field color="green" appearance="fill" [style.width.px]=300>
<mat-label>Start Date</mat-label>
<input matInput [matDatepicker]="picker2" [min]="minDateStart" [max]="maxDate" formControlName="startDate" on/>
<mat-error>
<p *ngIf="dateForm.controls.startDate.dirty && dateForm.controls.startDate.errors?.required" class="alert alert-danger">This is a required field</p>
<p *ngIf="dateForm.controls.startDate.dirty && dateForm.controls.startDate.errors?.invalidStartDate" class="alert alert-danger">
{{ dateForm.controls.startDate.errors?.invalidStartDate.message}} </p>
</mat-error>
<mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2 color="primary"></mat-datepicker>
</mat-form-field>
<mat-form-field color="green" appearance="fill" [style.width.px]=300>
<mat-label>End Date</mat-label>
<input matInput [matDatepicker]="picker3" [min]="minDateEnd" [max]="maxDate" formControlName="endDate"/>
<mat-error>
<p *ngIf="dateForm.controls.endDate.touched && dateForm.controls.endDate.errors?.required" class="alert alert-danger">This is a required field</p>
<p *ngIf="dateForm.errors?.invalidEndDate" class="alert alert-danger">
{{ dateForm.errors?.invalidEndDate.message}} </p>
</mat-error>
<mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle>
<mat-datepicker #picker3></mat-datepicker>
</mat-form-field>
</form>
我的TS文件-
const DATE_OFFSET_START = 1;
const DATE_OFFSET_END = 7;
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'Date Picker Validation Issue';
minDateStart: Date;
minDateEnd: Date;
maxDate: Date;
dateForm: FormGroup
constructor(
private formBuilder: FormBuilder) {
}
ngOnInit() {
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentDay = currentDate.getUTCDate();
const currentMonth = currentDate.getUTCMonth();
this.minDateEnd = new Date(currentYear, currentMonth, currentDay + DATE_OFFSET_START + DATE_OFFSET_END);
this.minDateStart = new Date(currentYear, currentMonth, currentDay + DATE_OFFSET_START);
this.maxDate = new Date(currentYear + 999, currentMonth, currentDay);
this.dateForm = this.formBuilder.group({
startDate: [this.minDateStart, [Validators.required, validateStartDate]],
endDate: [this.minDateEnd, [Validators.required]],
}, { validators: validateEndDate('startDate', 'endDate') });
}
}
// Validates the Form Group dates values.
// Returns error message if difference is less than specified limit.
export function validateEndDate(startDateFieldName: string, endDateFieldName: string) {
return (fg: FormGroup) => {
if (fg.get(endDateFieldName).value === undefined || fg.get(endDateFieldName).value == null)
return null;
let startDate = new Date(fg.get(startDateFieldName).value);
let endDate = new Date(fg.get(endDateFieldName).value);
return dateDifference(startDate, endDate) >= DATE_OFFSET_END ? null : {
invalidEndDate: {
message: "End Date should be atleast " + DATE_OFFSET_END + " days more than Start date!"
}
};
}
}
validateEndDate 是验证开始和结束日期的自定义验证器
{ validators: validateEndDate('startDate', 'endDate') });
这是显示错误的代码 -
<p *ngIf="dateForm.controls.endDate.touched && dateForm.controls.endDate.errors?.required" class="alert alert-danger">This is a required field</p>
<p *ngIf="dateForm.errors?.invalidEndDate" class="alert alert-danger">
{{ dateForm.errors?.invalidEndDate.message}} </p>
</mat-error>
我不确定为什么只有当日期小于 minDate 值时才显示错误,而不是所有验证错误。
我遇到这个问题不是因为我的自定义日期验证器,而是 angular material 表单的问题。我看到您没有在 <input>
标签中设置 errorStateMatcher
属性。当我使用这个 属性 时,一切正常。当你想检查父表单组是否无效时,你可以使用 matInput
的 errorStateMatcher
属性 ,如 doc.
中所述
例如:
HTML 中带有 errorStateMatcher 的到期日期字段:
<mat-form-field appearance="fill" class="full-width">
<mat-label>Due Date</mat-label>
<input matInput [matDatepicker]="picker"
formControlName="dueDate"
id="dueDate"
[min]="minDate"
[errorStateMatcher]="matcher">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker touchUi></mat-datepicker>
<mat-error *ngIf="createTaskForm.errors?.dueDateGtEqRepeatUntil">
DueDate should not be greater than or equal to Repeat Until Date.
</mat-error>
<mat-error *ngIf="createTaskForm.controls?.dueDate.hasError('required')">
Due date is required.
</mat-error>
</mat-form-field>
在 TS 文件中:
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const invalidCtrl = control && control.invalid;
const invalidParent = control && control.parent && control.parent.invalid;
return (invalidCtrl || invalidParent) && (control.dirty || control.touched);
}
}
我希望这能解决您的问题。有关两个日期字段之间交叉验证的其他详细信息,this video 可能会有用。
我有一个包含开始日期和结束日期的表格。开始日期应为第二天,结束日期应至少为开始日期后 7 天。我正在使用 Angular material datepicker 并为这两个字段设置 minDate 值。我在 FormGroup 级别有一个自定义验证器,它验证 7 天逻辑并在验证失败时显示结束日期字段的错误消息。
验证工作正常,如果我手动输入较早的结束日期,则会显示一条错误消息。但是,如果我将开始日期更改为未来日期,然后将 select 更改为结束日期以致验证失败,则不会显示错误消息。基本上只有日期早于最初设置的 minDate 值时才会显示错误消息。对于结束日期大于最小日期的任何验证失败,不会显示错误。
我的HTML代码-
<form [formGroup]="dateForm" >
<mat-form-field color="green" appearance="fill" [style.width.px]=300>
<mat-label>Start Date</mat-label>
<input matInput [matDatepicker]="picker2" [min]="minDateStart" [max]="maxDate" formControlName="startDate" on/>
<mat-error>
<p *ngIf="dateForm.controls.startDate.dirty && dateForm.controls.startDate.errors?.required" class="alert alert-danger">This is a required field</p>
<p *ngIf="dateForm.controls.startDate.dirty && dateForm.controls.startDate.errors?.invalidStartDate" class="alert alert-danger">
{{ dateForm.controls.startDate.errors?.invalidStartDate.message}} </p>
</mat-error>
<mat-datepicker-toggle matSuffix [for]="picker2"></mat-datepicker-toggle>
<mat-datepicker #picker2 color="primary"></mat-datepicker>
</mat-form-field>
<mat-form-field color="green" appearance="fill" [style.width.px]=300>
<mat-label>End Date</mat-label>
<input matInput [matDatepicker]="picker3" [min]="minDateEnd" [max]="maxDate" formControlName="endDate"/>
<mat-error>
<p *ngIf="dateForm.controls.endDate.touched && dateForm.controls.endDate.errors?.required" class="alert alert-danger">This is a required field</p>
<p *ngIf="dateForm.errors?.invalidEndDate" class="alert alert-danger">
{{ dateForm.errors?.invalidEndDate.message}} </p>
</mat-error>
<mat-datepicker-toggle matSuffix [for]="picker3"></mat-datepicker-toggle>
<mat-datepicker #picker3></mat-datepicker>
</mat-form-field>
</form>
我的TS文件-
const DATE_OFFSET_START = 1;
const DATE_OFFSET_END = 7;
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss']
})
export class AppComponent {
title = 'Date Picker Validation Issue';
minDateStart: Date;
minDateEnd: Date;
maxDate: Date;
dateForm: FormGroup
constructor(
private formBuilder: FormBuilder) {
}
ngOnInit() {
const currentDate = new Date();
const currentYear = currentDate.getFullYear();
const currentDay = currentDate.getUTCDate();
const currentMonth = currentDate.getUTCMonth();
this.minDateEnd = new Date(currentYear, currentMonth, currentDay + DATE_OFFSET_START + DATE_OFFSET_END);
this.minDateStart = new Date(currentYear, currentMonth, currentDay + DATE_OFFSET_START);
this.maxDate = new Date(currentYear + 999, currentMonth, currentDay);
this.dateForm = this.formBuilder.group({
startDate: [this.minDateStart, [Validators.required, validateStartDate]],
endDate: [this.minDateEnd, [Validators.required]],
}, { validators: validateEndDate('startDate', 'endDate') });
}
}
// Validates the Form Group dates values.
// Returns error message if difference is less than specified limit.
export function validateEndDate(startDateFieldName: string, endDateFieldName: string) {
return (fg: FormGroup) => {
if (fg.get(endDateFieldName).value === undefined || fg.get(endDateFieldName).value == null)
return null;
let startDate = new Date(fg.get(startDateFieldName).value);
let endDate = new Date(fg.get(endDateFieldName).value);
return dateDifference(startDate, endDate) >= DATE_OFFSET_END ? null : {
invalidEndDate: {
message: "End Date should be atleast " + DATE_OFFSET_END + " days more than Start date!"
}
};
}
}
validateEndDate 是验证开始和结束日期的自定义验证器
{ validators: validateEndDate('startDate', 'endDate') });
这是显示错误的代码 -
<p *ngIf="dateForm.controls.endDate.touched && dateForm.controls.endDate.errors?.required" class="alert alert-danger">This is a required field</p>
<p *ngIf="dateForm.errors?.invalidEndDate" class="alert alert-danger">
{{ dateForm.errors?.invalidEndDate.message}} </p>
</mat-error>
我不确定为什么只有当日期小于 minDate 值时才显示错误,而不是所有验证错误。
我遇到这个问题不是因为我的自定义日期验证器,而是 angular material 表单的问题。我看到您没有在 <input>
标签中设置 errorStateMatcher
属性。当我使用这个 属性 时,一切正常。当你想检查父表单组是否无效时,你可以使用 matInput
的 errorStateMatcher
属性 ,如 doc.
例如:
HTML 中带有 errorStateMatcher 的到期日期字段:
<mat-form-field appearance="fill" class="full-width">
<mat-label>Due Date</mat-label>
<input matInput [matDatepicker]="picker"
formControlName="dueDate"
id="dueDate"
[min]="minDate"
[errorStateMatcher]="matcher">
<mat-datepicker-toggle matSuffix [for]="picker"></mat-datepicker-toggle>
<mat-datepicker #picker touchUi></mat-datepicker>
<mat-error *ngIf="createTaskForm.errors?.dueDateGtEqRepeatUntil">
DueDate should not be greater than or equal to Repeat Until Date.
</mat-error>
<mat-error *ngIf="createTaskForm.controls?.dueDate.hasError('required')">
Due date is required.
</mat-error>
</mat-form-field>
在 TS 文件中:
export class MyErrorStateMatcher implements ErrorStateMatcher {
isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean {
const invalidCtrl = control && control.invalid;
const invalidParent = control && control.parent && control.parent.invalid;
return (invalidCtrl || invalidParent) && (control.dirty || control.touched);
}
}
我希望这能解决您的问题。有关两个日期字段之间交叉验证的其他详细信息,this video 可能会有用。