From 9b99a17f69c170245b9144f1a368888f1e9cd3de Mon Sep 17 00:00:00 2001 From: Tomasz Gnyp Date: Mon, 8 Jul 2024 14:49:59 +0200 Subject: [PATCH] update validation --- .../widgets/core/error-message.model.ts | 4 +- .../widgets/core/form-field-types.ts | 23 +- .../widgets/core/form-field-validator.ts | 245 ------------------ .../widgets/core/form-field.model.ts | 4 - .../components/widgets/core/form.model.ts | 18 +- .../widgets/date-time/date-time.widget.ts | 55 +++- .../components/widgets/date/date.widget.ts | 53 +++- .../widgets/date/date-cloud.widget.ts | 56 +++- 8 files changed, 168 insertions(+), 290 deletions(-) diff --git a/lib/core/src/lib/form/components/widgets/core/error-message.model.ts b/lib/core/src/lib/form/components/widgets/core/error-message.model.ts index ecba680bc87..a09ee2c9e2b 100644 --- a/lib/core/src/lib/form/components/widgets/core/error-message.model.ts +++ b/lib/core/src/lib/form/components/widgets/core/error-message.model.ts @@ -23,7 +23,7 @@ export class ErrorMessageModel { constructor(obj?: any) { this.message = obj?.message || ''; - this.attributes = new Map(); + this.attributes = obj?.attributes || new Map(); } isActive(): boolean { @@ -31,7 +31,7 @@ export class ErrorMessageModel { } getAttributesAsJsonObj() { - let result = {}; + const result = {}; if (this.attributes.size > 0) { this.attributes.forEach((value, key) => { result[key] = typeof value === 'string' ? value : JSON.stringify(value); diff --git a/lib/core/src/lib/form/components/widgets/core/form-field-types.ts b/lib/core/src/lib/form/components/widgets/core/form-field-types.ts index b934ec99455..f62cfd6ffea 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field-types.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field-types.ts @@ -15,7 +15,7 @@ * limitations under the License. */ - /* eslint-disable @angular-eslint/component-selector */ +/* eslint-disable @angular-eslint/component-selector */ export class FormFieldTypes { static CONTAINER: string = 'container'; @@ -50,20 +50,13 @@ export class FormFieldTypes { static DATA_TABLE: string = 'data-table'; static DISPLAY_EXTERNAL_PROPERTY: string = 'display-external-property'; - static READONLY_TYPES: string[] = [ - FormFieldTypes.HYPERLINK, - FormFieldTypes.DISPLAY_VALUE, - FormFieldTypes.READONLY_TEXT, - FormFieldTypes.GROUP - ]; + static READONLY_TYPES: string[] = [FormFieldTypes.HYPERLINK, FormFieldTypes.DISPLAY_VALUE, FormFieldTypes.READONLY_TEXT, FormFieldTypes.GROUP]; - static VALIDATABLE_TYPES: string[] = [ - FormFieldTypes.DISPLAY_EXTERNAL_PROPERTY - ]; + static VALIDATABLE_TYPES: string[] = [FormFieldTypes.DISPLAY_EXTERNAL_PROPERTY]; - static CONSTANT_VALUE_TYPES: string[] = [ - FormFieldTypes.DISPLAY_EXTERNAL_PROPERTY - ]; + static REACTIVE_TYPES: string[] = [FormFieldTypes.DATE, FormFieldTypes.DATETIME]; + + static CONSTANT_VALUE_TYPES: string[] = [FormFieldTypes.DISPLAY_EXTERNAL_PROPERTY]; static isReadOnlyType(type: string) { return FormFieldTypes.READONLY_TYPES.includes(type); @@ -73,6 +66,10 @@ export class FormFieldTypes { return FormFieldTypes.VALIDATABLE_TYPES.includes(type); } + static isReactiveType(type: string): boolean { + return FormFieldTypes.REACTIVE_TYPES.includes(type); + } + static isConstantValueType(type: string) { return FormFieldTypes.CONSTANT_VALUE_TYPES.includes(type); } diff --git a/lib/core/src/lib/form/components/widgets/core/form-field-validator.ts b/lib/core/src/lib/form/components/widgets/core/form-field-validator.ts index c1caa5baecf..aa28adafdad 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field-validator.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field-validator.ts @@ -20,9 +20,6 @@ import { FormFieldTypes } from './form-field-types'; import { isNumberValue } from './form-field-utils'; import { FormFieldModel } from './form-field.model'; -import { DateFnsUtils } from '../../../../common/utils/date-fns-utils'; -import { isValid as isDateValid, isBefore, isAfter } from 'date-fns'; -import { ErrorMessageModel } from './error-message.model'; export interface FormFieldValidator { isSupported(field: FormFieldModel): boolean; @@ -43,8 +40,6 @@ export class RequiredFieldValidator implements FormFieldValidator { FormFieldTypes.UPLOAD, FormFieldTypes.AMOUNT, FormFieldTypes.DYNAMIC_TABLE, - FormFieldTypes.DATE, - FormFieldTypes.DATETIME, FormFieldTypes.ATTACH_FOLDER, FormFieldTypes.DECIMAL, FormFieldTypes.DISPLAY_EXTERNAL_PROPERTY @@ -128,240 +123,6 @@ export class NumberFieldValidator implements FormFieldValidator { } } -export class DateFieldValidator implements FormFieldValidator { - private supportedTypes = new Set([FormFieldTypes.DATE]); - - static isValidDate(inputDate: string, dateFormat: string = 'D-M-YYYY'): boolean { - return DateFnsUtils.isValidDate(inputDate, dateFormat); - } - - isSupported(field: FormFieldModel): boolean { - return field && this.supportedTypes.has(field.type); - } - - skipValidation(field: FormFieldModel): boolean { - return !this.isSupported(field) || !field.isVisible; - } - - isInvalid(field: FormFieldModel): boolean { - const isValidDate = DateFieldValidator.isValidDate(field.value, field.dateDisplayFormat); - return !field.isValid || !isValidDate; - } - - isValid(field: FormFieldModel): boolean { - if (field.isValid && (!field.value || DateFieldValidator.isValidDate(field.value, field.dateDisplayFormat))) { - return true; - } - - return false; - } - - validate(field: FormFieldModel): boolean { - if (this.skipValidation(field)) { - return true; - } - - if (this.isValid(field)) { - return true; - } - - field.validationSummary = new ErrorMessageModel({ message: field.dateDisplayFormat || field.defaultDateFormat }); - return false; - } -} - -export class DateTimeFieldValidator implements FormFieldValidator { - private supportedTypes = new Set([FormFieldTypes.DATETIME]); - - static isValidDateTime(input: string): boolean { - const date = DateFnsUtils.getDate(input); - return isDateValid(date); - } - - isSupported(field: FormFieldModel): boolean { - return field && this.supportedTypes.has(field.type); - } - - skipValidation(field: FormFieldModel): boolean { - return !this.isSupported(field) || !field.isVisible; - } - - isValid(field: FormFieldModel): boolean { - if (field.isValid && (!field.value || DateTimeFieldValidator.isValidDateTime(field.value))) { - return true; - } - - return false; - } - - validate(field: FormFieldModel): boolean { - if (this.skipValidation(field)) { - return true; - } - - if (this.isValid(field)) { - return true; - } - - field.validationSummary = new ErrorMessageModel({ message: field.dateDisplayFormat || field.defaultDateTimeFormat }); - return false; - } -} - -export abstract class BoundaryDateFieldValidator implements FormFieldValidator { - DATE_FORMAT_CLOUD = 'YYYY-MM-DD'; - DATE_FORMAT = 'DD-MM-YYYY'; - - supportedTypes = [FormFieldTypes.DATE]; - - validate(field: FormFieldModel): boolean { - let isValid = true; - if (this.isSupported(field) && field.value && field.isVisible) { - const dateFormat = field.dateDisplayFormat; - - if (!DateFieldValidator.isValidDate(field.value, dateFormat)) { - field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE'; - isValid = false; - } else { - isValid = this.checkDate(field, dateFormat); - } - } - return isValid; - } - - extractDateFormat(date: string): string { - const brokenDownDate = date.split('-'); - return brokenDownDate[0].length === 4 ? this.DATE_FORMAT_CLOUD : this.DATE_FORMAT; - } - - abstract checkDate(field: FormFieldModel, dateFormat: string); - abstract isSupported(field: FormFieldModel); -} - -export class MinDateFieldValidator extends BoundaryDateFieldValidator { - checkDate(field: FormFieldModel, dateFormat: string): boolean { - let isValid = true; - const fieldValueData = DateFnsUtils.parseDate(field.value, dateFormat, { dateOnly: true }); - const minValueDateFormat = this.extractDateFormat(field.minValue); - const min = DateFnsUtils.parseDate(field.minValue, minValueDateFormat); - - if (DateFnsUtils.isBeforeDate(fieldValueData, min)) { - field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`; - field.validationSummary.attributes.set('minValue', DateFnsUtils.formatDate(min, field.dateDisplayFormat).toLocaleUpperCase()); - isValid = false; - } - return isValid; - } - - isSupported(field: FormFieldModel): boolean { - return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.minValue; - } -} - -export class MaxDateFieldValidator extends BoundaryDateFieldValidator { - checkDate(field: FormFieldModel, dateFormat: string): boolean { - let isValid = true; - const fieldValueData = DateFnsUtils.parseDate(field.value, dateFormat, { dateOnly: true }); - const maxValueDateFormat = this.extractDateFormat(field.maxValue); - const max = DateFnsUtils.parseDate(field.maxValue, maxValueDateFormat); - - if (DateFnsUtils.isAfterDate(fieldValueData, max)) { - field.validationSummary.message = `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`; - field.validationSummary.attributes.set('maxValue', DateFnsUtils.formatDate(max, field.dateDisplayFormat).toLocaleUpperCase()); - isValid = false; - } - return isValid; - } - - isSupported(field: FormFieldModel): boolean { - return field && this.supportedTypes.indexOf(field.type) > -1 && !!field.maxValue; - } -} - -export abstract class BoundaryDateTimeFieldValidator implements FormFieldValidator { - private supportedTypes = [FormFieldTypes.DATETIME]; - - isSupported(field: FormFieldModel): boolean { - return field && this.supportedTypes.indexOf(field.type) > -1 && !!field[this.getSubjectField()]; - } - - validate(field: FormFieldModel): boolean { - let isValid = true; - if (this.isSupported(field) && field.value && field.isVisible) { - if (!DateTimeFieldValidator.isValidDateTime(field.value)) { - field.validationSummary.message = 'FORM.FIELD.VALIDATOR.INVALID_DATE'; - isValid = false; - } else { - isValid = this.checkDateTime(field); - } - } - return isValid; - } - - private checkDateTime(field: FormFieldModel): boolean { - let isValid = true; - const fieldValueDate = DateFnsUtils.getDate(field.value); - const subjectFieldDate = DateFnsUtils.getDate(field[this.getSubjectField()]); - - if (this.compareDates(fieldValueDate, subjectFieldDate)) { - field.validationSummary.message = this.getErrorMessage(); - field.validationSummary.attributes.set(this.getSubjectField(), DateFnsUtils.formatDate(subjectFieldDate, field.dateDisplayFormat)); - isValid = false; - } - return isValid; - } - - protected abstract compareDates(fieldValueDate: Date, subjectFieldDate: Date): boolean; - - protected abstract getSubjectField(): string; - - protected abstract getErrorMessage(): string; -} - -/** - * Validates the min constraint for the datetime value. - * - * Notes for developers: - * the format of the min/max values is always the ISO datetime: i.e. 2023-10-01T15:21:00.000Z. - * Min/Max values can be parsed with standard `new Date(value)` calls. - * - */ -export class MinDateTimeFieldValidator extends BoundaryDateTimeFieldValidator { - protected compareDates(fieldValueDate: Date, subjectFieldDate: Date): boolean { - return isBefore(fieldValueDate, subjectFieldDate); - } - - protected getSubjectField(): string { - return 'minValue'; - } - - protected getErrorMessage(): string { - return `FORM.FIELD.VALIDATOR.NOT_LESS_THAN`; - } -} - -/** - * Validates the max constraint for the datetime value. - * - * Notes for developers: - * the format of the min/max values is always the ISO datetime: i.e. 2023-10-01T15:21:00.000Z. - * Min/Max values can be parsed with standard `new Date(value)` calls. - * - */ -export class MaxDateTimeFieldValidator extends BoundaryDateTimeFieldValidator { - protected compareDates(fieldValueDate: Date, subjectFieldDate: Date): boolean { - return isAfter(fieldValueDate, subjectFieldDate); - } - - protected getSubjectField(): string { - return 'maxValue'; - } - - protected getErrorMessage(): string { - return `FORM.FIELD.VALIDATOR.NOT_GREATER_THAN`; - } -} - export class MinLengthFieldValidator implements FormFieldValidator { private supportedTypes = [FormFieldTypes.TEXT, FormFieldTypes.MULTILINE_TEXT]; @@ -556,12 +317,6 @@ export const FORM_FIELD_VALIDATORS = [ new MinValueFieldValidator(), new MaxValueFieldValidator(), new RegExFieldValidator(), - new DateFieldValidator(), - new DateTimeFieldValidator(), - new MinDateFieldValidator(), - new MaxDateFieldValidator(), new FixedValueFieldValidator(), - new MinDateTimeFieldValidator(), - new MaxDateTimeFieldValidator(), new DecimalFieldValidator() ]; diff --git a/lib/core/src/lib/form/components/widgets/core/form-field.model.ts b/lib/core/src/lib/form/components/widgets/core/form-field.model.ts index 5c14ad3f5fb..b0ad4a1f639 100644 --- a/lib/core/src/lib/form/components/widgets/core/form-field.model.ts +++ b/lib/core/src/lib/form/components/widgets/core/form-field.model.ts @@ -143,10 +143,6 @@ export class FormFieldModel extends FormWidgetModel { this._isValid = false; } - markAsValid() { - this._isValid = true; - } - validate(): boolean { this.validationSummary = new ErrorMessageModel(); diff --git a/lib/core/src/lib/form/components/widgets/core/form.model.ts b/lib/core/src/lib/form/components/widgets/core/form.model.ts index 4c32b15dd7e..facdf2846f5 100644 --- a/lib/core/src/lib/form/components/widgets/core/form.model.ts +++ b/lib/core/src/lib/form/components/widgets/core/form.model.ts @@ -148,13 +148,13 @@ export class FormModel implements ProcessFormModel { validateForm(): void { const validateFormEvent: any = new ValidateFormEvent(this); - const errorsField: FormFieldModel[] = []; - - for (let i = 0; i < this.fieldsCache.length; i++) { - if (!this.fieldsCache[i].validate()) { - errorsField.push(this.fieldsCache[i]); + const errorsField: FormFieldModel[] = this.fieldsCache.filter((field) => { + if (!FormFieldTypes.isReactiveType(field.type)) { + return !field.validate(); + } else { + return field.validationSummary.isActive(); } - } + }); this.isValid = errorsField.length <= 0; @@ -191,8 +191,10 @@ export class FormModel implements ProcessFormModel { return; } - if (!field.validate()) { - this.markAsInvalid(); + if (!FormFieldTypes.isReactiveType(field.type)) { + if (!field.validate()) { + this.markAsInvalid(); + } } this.validateForm(); diff --git a/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.ts b/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.ts index 9423806cdcb..f1f95cd9207 100644 --- a/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.ts +++ b/lib/core/src/lib/form/components/widgets/date-time/date-time.widget.ts @@ -19,7 +19,7 @@ import { NgIf } from '@angular/common'; import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; @@ -31,6 +31,7 @@ import { FormService } from '../../../services/form.service'; import { ErrorWidgetComponent } from '../error/error.component'; import { WidgetComponent } from '../widget.component'; import { Subscription } from 'rxjs'; +import { ErrorMessageModel } from '../core/error-message.model'; @Component({ selector: 'date-time-widget', @@ -63,7 +64,11 @@ export class DateTimeWidgetComponent extends WidgetComponent implements OnInit, private datetimeChangesSubscription: Subscription; - constructor(public formService: FormService, private dateAdapter: DateAdapter, private dateTimeAdapter: DatetimeAdapter) { + constructor( + public readonly formService: FormService, + private readonly dateAdapter: DateAdapter, + private readonly dateTimeAdapter: DatetimeAdapter + ) { super(formService); } @@ -86,14 +91,52 @@ export class DateTimeWidgetComponent extends WidgetComponent implements OnInit, private subscribeToDateChanges(): void { this.datetimeChangesSubscription = this.datetimeInputControl.valueChanges.subscribe((newDate: Date) => { - this.field.value = newDate.toISOString(); - this.checkErrors(); + this.field.value = newDate; + this.validateField(); this.onFieldChanged(this.field); }); } - private checkErrors(): void { - this.datetimeInputControl.invalid ? this.field.markAsInvalid() : this.field.markAsValid(); + private validateField(): void { + if (this.datetimeInputControl.invalid) { + this.handleErrors(this.datetimeInputControl.errors); + } else { + this.resetErrors(); + } + } + + private handleErrors(errors: ValidationErrors): void { + const errorAttributes = new Map(); + switch (true) { + case !!errors.matDatepickerParse: + this.updateValidationSummary(this.field.dateDisplayFormat || this.field.defaultDateTimeFormat); + break; + case !!errors.required: + this.updateValidationSummary('FORM.FIELD.REQUIRED'); + break; + case !!errors.matDatepickerMin: { + const minValue = DateFnsUtils.formatDate(errors.matDatepickerMin.min, this.field.dateDisplayFormat).toLocaleUpperCase(); + errorAttributes.set('minValue', minValue); + this.updateValidationSummary('FORM.FIELD.VALIDATOR.NOT_LESS_THAN', errorAttributes); + break; + } + case !!errors.matDatepickerMax: { + const maxValue = DateFnsUtils.formatDate(errors.matDatepickerMax.max, this.field.dateDisplayFormat).toLocaleUpperCase(); + errorAttributes.set('maxValue', maxValue); + this.updateValidationSummary('FORM.FIELD.VALIDATOR.NOT_GREATER_THAN', errorAttributes); + break; + } + default: + break; + } + } + + private updateValidationSummary(message: string, attributes?: Map): void { + this.field.validationSummary = new ErrorMessageModel({ message, attributes }); + } + + private resetErrors(): void { + this.updateValidationSummary(''); } private initDateAdapter(): void { diff --git a/lib/core/src/lib/form/components/widgets/date/date.widget.ts b/lib/core/src/lib/form/components/widgets/date/date.widget.ts index 2665ef6e4b3..55472e1854c 100644 --- a/lib/core/src/lib/form/components/widgets/date/date.widget.ts +++ b/lib/core/src/lib/form/components/widgets/date/date.widget.ts @@ -19,17 +19,18 @@ import { NgIf } from '@angular/common'; import { Component, OnDestroy, OnInit, ViewEncapsulation } from '@angular/core'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { MatFormFieldModule } from '@angular/material/form-field'; import { MatInputModule } from '@angular/material/input'; import { TranslateModule } from '@ngx-translate/core'; import { Subscription } from 'rxjs'; -import { ADF_DATE_FORMATS, AdfDateFnsAdapter } from '../../../../common'; +import { ADF_DATE_FORMATS, AdfDateFnsAdapter, DateFnsUtils } from '../../../../common'; import { FormService } from '../../../services/form.service'; import { ErrorWidgetComponent } from '../error/error.component'; import { WidgetComponent } from '../widget.component'; +import { ErrorMessageModel } from '../core/error-message.model'; @Component({ selector: 'date-widget', @@ -60,11 +61,11 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit, OnDe maxDate: Date; startAt: Date; - dateInputControl: FormControl; + dateInputControl: FormControl; private dateChangesSubscription: Subscription; - constructor(public formService: FormService, private dateAdapter: DateAdapter) { + constructor(public readonly formService: FormService, private readonly dateAdapter: DateAdapter) { super(formService); } @@ -89,13 +90,51 @@ export class DateWidgetComponent extends WidgetComponent implements OnInit, OnDe private subscribeToDateChanges(): void { this.dateChangesSubscription = this.dateInputControl.valueChanges.subscribe((newDate: Date) => { this.field.value = newDate; - this.checkErrors(); + this.validateField(); this.onFieldChanged(this.field); }); } - private checkErrors(): void { - this.dateInputControl.invalid ? this.field.markAsInvalid() : this.field.markAsValid(); + private validateField(): void { + if (this.dateInputControl.invalid) { + this.handleErrors(this.dateInputControl.errors); + } else { + this.resetErrors(); + } + } + + private handleErrors(errors: ValidationErrors): void { + const errorAttributes = new Map(); + switch (true) { + case !!errors.matDatepickerParse: + this.updateValidationSummary(this.field.dateDisplayFormat || this.field.defaultDateTimeFormat); + break; + case !!errors.required: + this.updateValidationSummary('FORM.FIELD.REQUIRED'); + break; + case !!errors.matDatepickerMin: { + const minValue = DateFnsUtils.formatDate(errors.matDatepickerMin.min, this.field.dateDisplayFormat).toLocaleUpperCase(); + errorAttributes.set('minValue', minValue); + this.updateValidationSummary('FORM.FIELD.VALIDATOR.NOT_LESS_THAN', errorAttributes); + break; + } + case !!errors.matDatepickerMax: { + const maxValue = DateFnsUtils.formatDate(errors.matDatepickerMax.max, this.field.dateDisplayFormat).toLocaleUpperCase(); + errorAttributes.set('maxValue', maxValue); + this.updateValidationSummary('FORM.FIELD.VALIDATOR.NOT_GREATER_THAN', errorAttributes); + break; + } + default: + break; + } + } + + private updateValidationSummary(message: string, attributes?: Map): void { + this.field.validationSummary = new ErrorMessageModel({ message, attributes }); + } + + private resetErrors(): void { + this.updateValidationSummary(''); } private initDateAdapter(): void { diff --git a/lib/process-services-cloud/src/lib/form/components/widgets/date/date-cloud.widget.ts b/lib/process-services-cloud/src/lib/form/components/widgets/date/date-cloud.widget.ts index cf86e772cf0..1a2b558354f 100644 --- a/lib/process-services-cloud/src/lib/form/components/widgets/date/date-cloud.widget.ts +++ b/lib/process-services-cloud/src/lib/form/components/widgets/date/date-cloud.widget.ts @@ -20,10 +20,18 @@ import { Component, OnInit, ViewEncapsulation, OnDestroy } from '@angular/core'; import { DateAdapter, MAT_DATE_FORMATS } from '@angular/material/core'; import { Subscription } from 'rxjs'; -import { WidgetComponent, FormService, AdfDateFnsAdapter, DateFnsUtils, ADF_DATE_FORMATS, ErrorWidgetComponent } from '@alfresco/adf-core'; +import { + WidgetComponent, + FormService, + AdfDateFnsAdapter, + DateFnsUtils, + ADF_DATE_FORMATS, + ErrorWidgetComponent, + ErrorMessageModel +} from '@alfresco/adf-core'; import { MatDatepickerModule } from '@angular/material/datepicker'; import { addDays } from 'date-fns'; -import { FormControl, ReactiveFormsModule, Validators } from '@angular/forms'; +import { FormControl, ReactiveFormsModule, ValidationErrors, Validators } from '@angular/forms'; import { NgIf } from '@angular/common'; import { TranslateModule } from '@ngx-translate/core'; import { MatFormFieldModule } from '@angular/material/form-field'; @@ -99,13 +107,51 @@ export class DateCloudWidgetComponent extends WidgetComponent implements OnInit, private subscribeToDateChanges(): void { this.dateChangesSubscription = this.dateInputControl.valueChanges.subscribe((newDate: any) => { this.field.value = newDate; - this.checkErrors(); + this.validateField(); this.onFieldChanged(this.field); }); } - private checkErrors(): void { - this.dateInputControl.invalid ? this.field.markAsInvalid() : this.field.markAsValid(); + private validateField(): void { + if (this.dateInputControl.invalid) { + this.handleErrors(this.dateInputControl.errors); + } else { + this.resetErrors(); + } + } + + private handleErrors(errors: ValidationErrors): void { + const errorAttributes = new Map(); + switch (true) { + case !!errors.matDatepickerParse: + this.updateValidationSummary(this.field.dateDisplayFormat || this.field.defaultDateTimeFormat); + break; + case !!errors.required: + this.updateValidationSummary('FORM.FIELD.REQUIRED'); + break; + case !!errors.matDatepickerMin: { + const minValue = DateFnsUtils.formatDate(errors.matDatepickerMin.min, this.field.dateDisplayFormat).toLocaleUpperCase(); + errorAttributes.set('minValue', minValue); + this.updateValidationSummary('FORM.FIELD.VALIDATOR.NOT_LESS_THAN', errorAttributes); + break; + } + case !!errors.matDatepickerMax: { + const maxValue = DateFnsUtils.formatDate(errors.matDatepickerMax.max, this.field.dateDisplayFormat).toLocaleUpperCase(); + errorAttributes.set('maxValue', maxValue); + this.updateValidationSummary('FORM.FIELD.VALIDATOR.NOT_GREATER_THAN', errorAttributes); + break; + } + default: + break; + } + } + + private updateValidationSummary(message: string, attributes?: Map): void { + this.field.validationSummary = new ErrorMessageModel({ message, attributes }); + } + + private resetErrors(): void { + this.updateValidationSummary(''); } private initDateAdapter(): void {