Skip to content

Commit

Permalink
update validation
Browse files Browse the repository at this point in the history
  • Loading branch information
tomgny committed Jul 8, 2024
1 parent 964380a commit 9b99a17
Show file tree
Hide file tree
Showing 8 changed files with 168 additions and 290 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ export class ErrorMessageModel {

constructor(obj?: any) {
this.message = obj?.message || '';
this.attributes = new Map();
this.attributes = obj?.attributes || new Map();
}

isActive(): boolean {
return !!this.message;
}

getAttributesAsJsonObj() {
let result = {};
const result = {};
if (this.attributes.size > 0) {
this.attributes.forEach((value, key) => {
result[key] = typeof value === 'string' ? value : JSON.stringify(value);
Expand Down
23 changes: 10 additions & 13 deletions lib/core/src/lib/form/components/widgets/core/form-field-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down
245 changes: 0 additions & 245 deletions lib/core/src/lib/form/components/widgets/core/form-field-validator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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
Expand Down Expand Up @@ -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];

Expand Down Expand Up @@ -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()
];
Original file line number Diff line number Diff line change
Expand Up @@ -143,10 +143,6 @@ export class FormFieldModel extends FormWidgetModel {
this._isValid = false;
}

markAsValid() {
this._isValid = true;
}

validate(): boolean {
this.validationSummary = new ErrorMessageModel();

Expand Down
18 changes: 10 additions & 8 deletions lib/core/src/lib/form/components/widgets/core/form.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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();
Expand Down
Loading

0 comments on commit 9b99a17

Please sign in to comment.