mirror of
https://github.com/Alfresco/alfresco-ng2-components.git
synced 2025-10-08 14:51:32 +00:00
[ADF-1312] form validation enhancements (#2180)
* validation api enhancements - changing 'required' causes re-validation of the form - get field by id * allow binding field validators from html * demo validator * documentation updates * fix after rebase * markdown fixes * markdown linter settings for workspace config (vs code) * restore material theme
This commit is contained in:
committed by
Mario Romano
parent
6c1a758561
commit
3d65b49af7
@@ -22,7 +22,7 @@ import { EcmModelService } from './../services/ecm-model.service';
|
||||
import { FormService } from './../services/form.service';
|
||||
import { NodeService } from './../services/node.service';
|
||||
import { ContentLinkModel } from './widgets/core/content-link.model';
|
||||
import { FormFieldModel, FormModel, FormOutcomeEvent, FormOutcomeModel, FormValues } from './widgets/core/index';
|
||||
import { FormFieldModel, FormModel, FormOutcomeEvent, FormOutcomeModel, FormValues, FormFieldValidator } from './widgets/core/index';
|
||||
|
||||
import { WidgetVisibilityService } from './../services/widget-visibility.service';
|
||||
|
||||
@@ -90,6 +90,9 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
@Input()
|
||||
showValidationIcon: boolean = true;
|
||||
|
||||
@Input()
|
||||
fieldValidators: FormFieldValidator[] = [];
|
||||
|
||||
@Output()
|
||||
formSaved: EventEmitter<FormModel> = new EventEmitter<FormModel>();
|
||||
|
||||
@@ -307,16 +310,16 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
this.formService
|
||||
.getTaskForm(taskId)
|
||||
.subscribe(
|
||||
form => {
|
||||
this.form = new FormModel(form, this.data, this.readOnly, this.formService);
|
||||
this.onFormLoaded(this.form);
|
||||
resolve(this.form);
|
||||
},
|
||||
error => {
|
||||
this.handleError(error);
|
||||
// reject(error);
|
||||
resolve(null);
|
||||
}
|
||||
form => {
|
||||
this.form = this.parseForm(form);
|
||||
this.onFormLoaded(this.form);
|
||||
resolve(this.form);
|
||||
},
|
||||
error => {
|
||||
this.handleError(error);
|
||||
// reject(error);
|
||||
resolve(null);
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
@@ -396,6 +399,10 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
if (!json.fields) {
|
||||
form.outcomes = this.getFormDefinitionOutcomes(form);
|
||||
}
|
||||
if (this.fieldValidators && this.fieldValidators.length > 0) {
|
||||
console.log('Applying custom field validators');
|
||||
form.fieldValidators = this.fieldValidators;
|
||||
}
|
||||
return form;
|
||||
}
|
||||
return null;
|
||||
@@ -419,7 +426,7 @@ export class FormComponent implements OnInit, OnChanges {
|
||||
}
|
||||
|
||||
private refreshFormData() {
|
||||
this.form = new FormModel(this.form.json, this.data, this.readOnly, this.formService);
|
||||
this.form = this.parseForm(this.form.json);
|
||||
this.onFormLoaded(this.form);
|
||||
this.onFormDataRefreshed(this.form);
|
||||
}
|
||||
|
@@ -355,3 +355,16 @@ export class RegExFieldValidator implements FormFieldValidator {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export const FORM_FIELD_VALIDATORS = [
|
||||
new RequiredFieldValidator(),
|
||||
new NumberFieldValidator(),
|
||||
new MinLengthFieldValidator(),
|
||||
new MaxLengthFieldValidator(),
|
||||
new MinValueFieldValidator(),
|
||||
new MaxValueFieldValidator(),
|
||||
new RegExFieldValidator(),
|
||||
new DateFieldValidator(),
|
||||
new MinDateFieldValidator(),
|
||||
new MaxDateFieldValidator()
|
||||
];
|
||||
|
@@ -32,6 +32,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
private _value: string;
|
||||
private _readOnly: boolean = false;
|
||||
private _isValid: boolean = true;
|
||||
private _required: boolean = false;
|
||||
|
||||
readonly defaultDateFormat: string = 'D-M-YYYY';
|
||||
|
||||
@@ -40,7 +41,6 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
id: string;
|
||||
name: string;
|
||||
type: string;
|
||||
required: boolean;
|
||||
overrideId: boolean;
|
||||
tab: string;
|
||||
rowspan: number = 1;
|
||||
@@ -99,6 +99,15 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.updateForm();
|
||||
}
|
||||
|
||||
get required(): boolean {
|
||||
return this._required;
|
||||
}
|
||||
|
||||
set required(value: boolean) {
|
||||
this._required = value;
|
||||
this.updateForm();
|
||||
}
|
||||
|
||||
get isValid(): boolean {
|
||||
return this._isValid;
|
||||
}
|
||||
@@ -126,7 +135,7 @@ export class FormFieldModel extends FormWidgetModel {
|
||||
this.id = json.id;
|
||||
this.name = json.name;
|
||||
this.type = json.type;
|
||||
this.required = <boolean> json.required;
|
||||
this._required = <boolean> json.required;
|
||||
this._readOnly = <boolean> json.readOnly || json.type === 'readonly';
|
||||
this.overrideId = <boolean> json.overrideId;
|
||||
this.tab = json.tab;
|
||||
|
@@ -20,6 +20,8 @@ import { ValidateFormEvent } from './../../../events/validate-form.event';
|
||||
import { FormService } from './../../../services/form.service';
|
||||
import { ContainerModel } from './container.model';
|
||||
import { FormFieldTypes } from './form-field-types';
|
||||
import { FORM_FIELD_VALIDATORS, FormFieldValidator } from './form-field-validator';
|
||||
import { FormFieldModel } from './form-field.model';
|
||||
import { FormOutcomeModel } from './form-outcome.model';
|
||||
import { FormModel } from './form.model';
|
||||
import { TabModel } from './tab.model';
|
||||
@@ -381,4 +383,67 @@ describe('FormModel', () => {
|
||||
expect(field.validate).not.toHaveBeenCalled();
|
||||
expect(form.validateForm).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should get field by id', () => {
|
||||
const form = new FormModel({}, null, false, formService);
|
||||
const field = { id: 'field1' };
|
||||
spyOn(form, 'getFormFields').and.returnValue([field]);
|
||||
|
||||
const result = form.getFieldById('field1');
|
||||
expect(result).toBe(field);
|
||||
});
|
||||
|
||||
it('should use custom field validator', () => {
|
||||
const form = new FormModel({}, null, false, formService);
|
||||
const testField = new FormFieldModel(form, {
|
||||
id: 'test-field-1'
|
||||
});
|
||||
|
||||
spyOn(form, 'getFormFields').and.returnValue([testField]);
|
||||
|
||||
let validator = <FormFieldValidator> {
|
||||
isSupported(field: FormFieldModel): boolean {
|
||||
return true;
|
||||
},
|
||||
validate(field: FormFieldModel): boolean {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
spyOn(validator, 'validate').and.callThrough();
|
||||
|
||||
form.fieldValidators = [validator];
|
||||
form.validateForm();
|
||||
|
||||
expect(validator.validate).toHaveBeenCalledWith(testField);
|
||||
});
|
||||
|
||||
it('should re-validate the field when required attribute changes', () => {
|
||||
const form = new FormModel({}, null, false, formService);
|
||||
const testField = new FormFieldModel(form, {
|
||||
id: 'test-field-1',
|
||||
required: false
|
||||
});
|
||||
|
||||
spyOn(form, 'getFormFields').and.returnValue([testField]);
|
||||
spyOn(form, 'onFormFieldChanged').and.callThrough();
|
||||
spyOn(form, 'validateField').and.callThrough();
|
||||
|
||||
testField.required = true;
|
||||
|
||||
expect(testField.required).toBeTruthy();
|
||||
expect(form.onFormFieldChanged).toHaveBeenCalledWith(testField);
|
||||
expect(form.validateField).toHaveBeenCalledWith(testField);
|
||||
});
|
||||
|
||||
it('should not change default validators export', () => {
|
||||
const form = new FormModel({}, null, false, formService);
|
||||
const defaultLength = FORM_FIELD_VALIDATORS.length;
|
||||
|
||||
expect(form.fieldValidators.length).toBe(defaultLength);
|
||||
form.fieldValidators.push(<any> {});
|
||||
|
||||
expect(form.fieldValidators.length).toBe(defaultLength + 1);
|
||||
expect(FORM_FIELD_VALIDATORS.length).toBe(defaultLength);
|
||||
});
|
||||
});
|
||||
|
@@ -29,17 +29,8 @@ import { FormWidgetModel, FormWidgetModelCache } from './form-widget.model';
|
||||
import { TabModel } from './tab.model';
|
||||
|
||||
import {
|
||||
DateFieldValidator,
|
||||
FormFieldValidator,
|
||||
MaxDateFieldValidator,
|
||||
MaxLengthFieldValidator,
|
||||
MaxValueFieldValidator,
|
||||
MinDateFieldValidator,
|
||||
MinLengthFieldValidator,
|
||||
MinValueFieldValidator,
|
||||
NumberFieldValidator,
|
||||
RegExFieldValidator,
|
||||
RequiredFieldValidator
|
||||
FORM_FIELD_VALIDATORS,
|
||||
FormFieldValidator
|
||||
} from './form-field-validator';
|
||||
|
||||
export class FormModel {
|
||||
@@ -67,7 +58,7 @@ export class FormModel {
|
||||
fields: FormWidgetModel[] = [];
|
||||
outcomes: FormOutcomeModel[] = [];
|
||||
customFieldTemplates: FormFieldTemplates = {};
|
||||
fieldValidators: FormFieldValidator[] = [];
|
||||
fieldValidators: FormFieldValidator[] = [...FORM_FIELD_VALIDATORS];
|
||||
readonly selectedOutcome: string;
|
||||
|
||||
values: FormValues = {};
|
||||
@@ -138,19 +129,6 @@ export class FormModel {
|
||||
}
|
||||
}
|
||||
|
||||
this.fieldValidators = [
|
||||
new RequiredFieldValidator(),
|
||||
new NumberFieldValidator(),
|
||||
new MinLengthFieldValidator(),
|
||||
new MaxLengthFieldValidator(),
|
||||
new MinValueFieldValidator(),
|
||||
new MaxValueFieldValidator(),
|
||||
new RegExFieldValidator(),
|
||||
new DateFieldValidator(),
|
||||
new MinDateFieldValidator(),
|
||||
new MaxDateFieldValidator()
|
||||
];
|
||||
|
||||
this.validateForm();
|
||||
}
|
||||
|
||||
@@ -161,6 +139,10 @@ export class FormModel {
|
||||
}
|
||||
}
|
||||
|
||||
getFieldById(fieldId: string): FormFieldModel {
|
||||
return this.getFormFields().find(field => field.id === fieldId);
|
||||
}
|
||||
|
||||
// TODO: consider evaluating and caching once the form is loaded
|
||||
getFormFields(): FormFieldModel[] {
|
||||
let result: FormFieldModel[] = [];
|
||||
|
Reference in New Issue
Block a user