#angular #datepicker #angular-material #angular-validation #angular-custom-validators
#angular #datepicker #angular-material #angular-проверка #angular-custom-validators
Вопрос:
У меня есть форма с датой начала и датой окончания. Дата начала должна быть со следующего дня, а Дата окончания должна быть не менее 7 дней с момента начала. Я использую Angular material datepicker и устанавливаю значения minDate для обоих этих полей. У меня есть пользовательский валидатор на уровне FormGroup, который проверяет логику 7 дней и отображает сообщение об ошибке для поля Даты окончания, если проверка завершается неудачно.
Проверка работает нормально, и если я вручную введу более старую дату для даты окончания, отображается сообщение об ошибке. Но если я изменю начальную дату на будущую, а затем выберу Конечную дату, чтобы проверка завершилась неудачно, сообщение об ошибке не отображается. По сути, сообщение об ошибке отображается только в том случае, если дата старше, чем изначально заданное значение minDate. При любых сбоях проверки, когда Конечная дата больше, чем значение 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 amp;amp; dateForm.controls.startDate.errors?.required" class="alert alert-danger">This is a required field</p>
<p *ngIf="dateForm.controls.startDate.dirty amp;amp; 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>
amp;nbsp;
<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 amp;amp; 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 amp;amp; 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, а не для всех ошибок проверки.
Ответ №1:
Я столкнулся с этой проблемой не из-за моего пользовательского средства проверки дат, а из-за угловых материальных форм. Я вижу, что вы не установили errorStateMatcher
свойство в <input>
теге. Когда я использовал это свойство, все работало нормально. Если вы хотите проверить, является ли родительская группа форм недопустимой, вы можете использовать errorStateMatcher
свойство matInput
, как описано в этом документе.
Например:
Поле DueDate с errorStateMatcher в HTML:
<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 amp;amp; control.invalid;
const invalidParent = control amp;amp; control.parent amp;amp; control.parent.invalid;
return (invalidCtrl || invalidParent) amp;amp; (control.dirty || control.touched);
}
}
Я надеюсь, что это исправит вашу проблему. Для получения других подробных сведений о перекрестной проверке между двумя полями даты это видео может быть полезно.
Комментарии:
1. Спасибо, это сработало как шарм. Я удалил
amp;amp; (control.dirty || control.touched)
условие, чтобы ошибка отображалась при изменении начальной даты.2. Когда я использую его в своей существующей форме, если какое-либо из других полей в форме недопустимо, то это поле также выделялось как ошибка из-за
control.parent.invalid
условия. Я изменил метод для проверки наличия конкретных ошибок, чтобы решить эту проблему.const invalidCtrl = control amp;amp; control.invalid; const invalidEndDate = control amp;amp; control.parent amp;amp; control.parent.hasError('invalidEndDate'); return (invalidCtrl || invalidEndDate);