Fixed form error handler

This commit is contained in:
Giuseppe Digilio
2018-07-10 15:25:36 +02:00
parent 1f02a4cb5b
commit 9b249f00df
7 changed files with 59 additions and 33 deletions

View File

@@ -85,7 +85,7 @@ export const FORM_GROUP_TEST_GROUP = new FormGroup({
dc_contributor_author: new FormControl(), dc_contributor_author: new FormControl(),
}); });
describe('DsDynamicGroupComponent test suite', () => { fdescribe('DsDynamicGroupComponent test suite', () => {
const config = { const config = {
form: { form: {
validatorMap: { validatorMap: {
@@ -188,8 +188,8 @@ describe('DsDynamicGroupComponent test suite', () => {
}); });
it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => { it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
const config = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel; const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel;
const formModel = service.modelFromConfiguration(config, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly); const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const chips = new Chips([], 'value', 'dc.contributor.author'); const chips = new Chips([], 'value', 'dc.contributor.author');
expect(groupComp.formCollapsed).toEqual(Observable.of(false)); expect(groupComp.formCollapsed).toEqual(Observable.of(false));
@@ -258,8 +258,8 @@ describe('DsDynamicGroupComponent test suite', () => {
}); });
it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => { it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => {
const config = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel; const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel;
const formModel = service.modelFromConfiguration(config, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly); const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly);
const chips = new Chips(modelValue, 'value', 'dc.contributor.author'); const chips = new Chips(modelValue, 'value', 'dc.contributor.author');
expect(groupComp.formCollapsed).toEqual(Observable.of(true)); expect(groupComp.formCollapsed).toEqual(Observable.of(true));

View File

@@ -43,6 +43,19 @@ export class DynamicGroupModel extends DsDynamicInputModel {
} }
get value() { get value() {
return this._value
}
set value(value) {
this._value = (isEmpty(value)) ? null : value;
}
isEmpty() {
const value = this.getGroupValue();
return (value.length === 1 && isNull(value[0][this.mandatoryField]));
}
getGroupValue(): any[] {
if (isEmpty(this._value)) { if (isEmpty(this._value)) {
// If items is empty, last element has been removed // If items is empty, last element has been removed
// so emit an empty value that allows to dispatch // so emit an empty value that allows to dispatch
@@ -57,12 +70,4 @@ export class DynamicGroupModel extends DsDynamicInputModel {
} }
return this._value return this._value
} }
set value(value) {
this._value = value;
}
isEmpty() {
return (this.value.length === 1 && isNull(this.value[0][this.mandatoryField]));
}
} }

View File

@@ -18,7 +18,10 @@ import { isObject, isString, mergeWith } from 'lodash';
import { hasValue, isEmpty, isNotEmpty, isNotNull, isNotUndefined, isNull } from '../../empty.util'; import { hasValue, isEmpty, isNotEmpty, isNotNull, isNotUndefined, isNull } from '../../empty.util';
import { DynamicQualdropModel } from './ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model'; import { DynamicQualdropModel } from './ds-dynamic-form-ui/models/ds-dynamic-qualdrop.model';
import { SubmissionFormsModel } from '../../../core/shared/config/config-submission-forms.model'; import { SubmissionFormsModel } from '../../../core/shared/config/config-submission-forms.model';
import { DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP } from './ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; import {
DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP,
DynamicGroupModel
} from './ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model';
import { DYNAMIC_FORM_CONTROL_TYPE_TAG } from './ds-dynamic-form-ui/models/tag/dynamic-tag.model'; import { DYNAMIC_FORM_CONTROL_TYPE_TAG } from './ds-dynamic-form-ui/models/tag/dynamic-tag.model';
import { RowParser } from './parsers/row-parser'; import { RowParser } from './parsers/row-parser';
@@ -150,7 +153,7 @@ export class FormBuilderService extends DynamicFormService {
} }
if (this.isRelationGroup(controlModel)) { if (this.isRelationGroup(controlModel)) {
const values = (controlModel as any).value; const values = (controlModel as DynamicGroupModel).getGroupValue();
values.forEach((groupValue, groupIndex) => { values.forEach((groupValue, groupIndex) => {
const newGroupValue = Object.create({}); const newGroupValue = Object.create({});
Object.keys(groupValue) Object.keys(groupValue)

View File

@@ -106,11 +106,12 @@ export class FormAddError implements Action {
payload: { payload: {
formId: string, formId: string,
fieldId: string, fieldId: string,
fieldIndex: number,
errorMessage: string, errorMessage: string,
}; };
constructor(formId: string, fieldId: string, errorMessage: string) { constructor(formId: string, fieldId: string, fieldIndex: number, errorMessage: string) {
this.payload = {formId, fieldId, errorMessage}; this.payload = {formId, fieldId, fieldIndex, errorMessage};
} }
} }
@@ -118,11 +119,12 @@ export class FormRemoveErrorAction implements Action {
type = FormActionTypes.FORM_REMOVE_ERROR; type = FormActionTypes.FORM_REMOVE_ERROR;
payload: { payload: {
formId: string, formId: string,
fieldId: string fieldId: string,
fieldIndex: number,
}; };
constructor(formId: string, fieldId: string) { constructor(formId: string, fieldId: string, fieldIndex: number,) {
this.payload = {formId, fieldId}; this.payload = {formId, fieldId, fieldIndex};
} }
} }

View File

@@ -162,14 +162,15 @@ export class FormComponent implements OnDestroy, OnInit {
const {formGroup, formModel} = this; const {formGroup, formModel} = this;
errors errors
.filter((error: FormError) => findIndex(this.formErrors, {fieldId: error.fieldId}) === -1) .filter((error: FormError) => findIndex(this.formErrors, {fieldId: error.fieldId, fieldIndex: error.fieldIndex}) === -1)
.forEach((error: FormError) => { .forEach((error: FormError) => {
const {fieldId} = error; const {fieldId} = error;
const {fieldIndex} = error;
let field: AbstractControl; let field: AbstractControl;
if (!!this.parentFormModel) { if (!!this.parentFormModel) {
field = this.formBuilderService.getFormControlById(fieldId, formGroup.parent as FormGroup, formModel); field = this.formBuilderService.getFormControlById(fieldId, formGroup.parent as FormGroup, formModel, fieldIndex);
} else { } else {
field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel); field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel, fieldIndex);
} }
if (field) { if (field) {
@@ -181,14 +182,15 @@ export class FormComponent implements OnDestroy, OnInit {
}); });
this.formErrors this.formErrors
.filter((error: FormError) => findIndex(errors, {fieldId: error.fieldId}) === -1) .filter((error: FormError) => findIndex(errors, {fieldId: error.fieldId, fieldIndex: error.fieldIndex}) === -1)
.forEach((error: FormError) => { .forEach((error: FormError) => {
const {fieldId} = error; const {fieldId} = error;
const {fieldIndex} = error;
let field: AbstractControl; let field: AbstractControl;
if (!!this.parentFormModel) { if (!!this.parentFormModel) {
field = this.formBuilderService.getFormControlById(fieldId, formGroup.parent as FormGroup, formModel); field = this.formBuilderService.getFormControlById(fieldId, formGroup.parent as FormGroup, formModel, fieldIndex);
} else { } else {
field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel); field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel, fieldIndex);
} }
if (field) { if (field) {
@@ -251,8 +253,9 @@ export class FormComponent implements OnDestroy, OnInit {
} }
const control: FormControl = event.control; const control: FormControl = event.control;
const fieldIndex: number = (event.context && event.context.index) ? event.context.index : 0;
if (control.valid) { if (control.valid) {
this.store.dispatch(new FormRemoveErrorAction(this.formId, event.model.id)); this.store.dispatch(new FormRemoveErrorAction(this.formId, event.model.id, fieldIndex));
} }
} }

View File

@@ -1,9 +1,11 @@
import { FormEntry, formReducer } from './form.reducer'; import { formReducer } from './form.reducer';
import { import {
FormAddError, FormAddError,
FormChangeAction, FormClearErrorsAction, FormChangeAction,
FormClearErrorsAction,
FormInitAction, FormInitAction,
FormRemoveAction, FormRemoveErrorAction, FormRemoveAction,
FormRemoveErrorAction,
FormStatusChangeAction FormStatusChangeAction
} from './form.actions'; } from './form.actions';
@@ -165,15 +167,17 @@ describe('formReducer', () => {
const expectedErrors = [ const expectedErrors = [
{ {
fieldId: 'title', fieldId: 'title',
fieldIndex: 0,
message: 'Not valid' message: 'Not valid'
} }
]; ];
const formId = 'testForm'; const formId = 'testForm';
const fieldId = 'title'; const fieldId = 'title';
const fieldIndex = 0;
const message = 'Not valid'; const message = 'Not valid';
const action = new FormAddError(formId, fieldId, message); const action = new FormAddError(formId, fieldId, fieldIndex, message);
const newState = formReducer(initState, action); const newState = formReducer(initState, action);
expect(newState.testForm.errors).toEqual(expectedErrors); expect(newState.testForm.errors).toEqual(expectedErrors);
@@ -192,10 +196,12 @@ describe('formReducer', () => {
errors: [ errors: [
{ {
fieldId: 'author', fieldId: 'author',
fieldIndex: 0,
message: 'error.validation.required' message: 'error.validation.required'
}, },
{ {
fieldId: 'title', fieldId: 'title',
fieldIndex: 0,
message: 'error.validation.required' message: 'error.validation.required'
} }
] ]
@@ -205,13 +211,16 @@ describe('formReducer', () => {
const expectedErrors = [ const expectedErrors = [
{ {
fieldId: 'title', fieldId: 'title',
fieldIndex: 0,
message: 'error.validation.required' message: 'error.validation.required'
} }
]; ];
const formId = 'testForm'; const formId = 'testForm';
const fieldId = 'author';
const fieldIndex = 0;
const action = new FormRemoveErrorAction(formId, 'author'); const action = new FormRemoveErrorAction(formId, fieldId, fieldIndex);
const newState = formReducer(initState, action); const newState = formReducer(initState, action);
expect(newState.testForm.errors).toEqual(expectedErrors); expect(newState.testForm.errors).toEqual(expectedErrors);
@@ -252,6 +261,7 @@ describe('formReducer', () => {
errors: [ errors: [
{ {
fieldId: 'author', fieldId: 'author',
fieldIndex: 0,
message: 'error.validation.required' message: 'error.validation.required'
} }
] ]

View File

@@ -14,6 +14,7 @@ import { isEqual, uniqWith } from 'lodash';
export interface FormError { export interface FormError {
message: string; message: string;
fieldId: string; fieldId: string;
fieldIndex: number;
} }
export interface FormEntry { export interface FormEntry {
@@ -70,6 +71,7 @@ function addFormErrors(state: FormState, action: FormAddError) {
if (hasValue(state[formId])) { if (hasValue(state[formId])) {
const error: FormError = { const error: FormError = {
fieldId: action.payload.fieldId, fieldId: action.payload.fieldId,
fieldIndex: action.payload.fieldIndex,
message: action.payload.errorMessage message: action.payload.errorMessage
}; };
@@ -88,8 +90,9 @@ function addFormErrors(state: FormState, action: FormAddError) {
function removeFormError(state: FormState, action: FormRemoveErrorAction) { function removeFormError(state: FormState, action: FormRemoveErrorAction) {
const formId = action.payload.formId; const formId = action.payload.formId;
const fieldId = action.payload.fieldId; const fieldId = action.payload.fieldId;
const fieldIndex = action.payload.fieldIndex;
if (hasValue(state[formId])) { if (hasValue(state[formId])) {
const errors = state[formId].errors.filter((error) => error.fieldId !== fieldId); const errors = state[formId].errors.filter((error) => error.fieldId !== fieldId || error.fieldIndex !== fieldIndex);
const newState = Object.assign({}, state); const newState = Object.assign({}, state);
newState[formId] = Object.assign({}, state[formId], {errors}); newState[formId] = Object.assign({}, state[formId], {errors});
return newState; return newState;