diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.spec.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.spec.ts index 9b3d9f8342..5dbd456bea 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.spec.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.spec.ts @@ -85,7 +85,7 @@ export const FORM_GROUP_TEST_GROUP = new FormGroup({ dc_contributor_author: new FormControl(), }); -describe('DsDynamicGroupComponent test suite', () => { +fdescribe('DsDynamicGroupComponent test suite', () => { const config = { form: { validatorMap: { @@ -188,8 +188,8 @@ describe('DsDynamicGroupComponent test suite', () => { }); it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => { - const config = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel; - const formModel = service.modelFromConfiguration(config, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly); + const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel; + const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly); const chips = new Chips([], 'value', 'dc.contributor.author'); expect(groupComp.formCollapsed).toEqual(Observable.of(false)); @@ -258,8 +258,8 @@ describe('DsDynamicGroupComponent test suite', () => { }); it('should init component properly', inject([FormBuilderService], (service: FormBuilderService) => { - const config = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel; - const formModel = service.modelFromConfiguration(config, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly); + const formConfig = {rows: groupComp.model.formConfiguration} as SubmissionFormsModel; + const formModel = service.modelFromConfiguration(formConfig, groupComp.model.scopeUUID, {}, groupComp.model.submissionScope, groupComp.model.readOnly); const chips = new Chips(modelValue, 'value', 'dc.contributor.author'); expect(groupComp.formCollapsed).toEqual(Observable.of(true)); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model.ts index 570e4bd7ea..2048c41df8 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model.ts @@ -43,6 +43,19 @@ export class DynamicGroupModel extends DsDynamicInputModel { } 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 items is empty, last element has been removed // so emit an empty value that allows to dispatch @@ -57,12 +70,4 @@ export class DynamicGroupModel extends DsDynamicInputModel { } return this._value } - - set value(value) { - this._value = value; - } - - isEmpty() { - return (this.value.length === 1 && isNull(this.value[0][this.mandatoryField])); - } } diff --git a/src/app/shared/form/builder/form-builder.service.ts b/src/app/shared/form/builder/form-builder.service.ts index b87b9e4381..ec78225274 100644 --- a/src/app/shared/form/builder/form-builder.service.ts +++ b/src/app/shared/form/builder/form-builder.service.ts @@ -18,7 +18,10 @@ import { isObject, isString, mergeWith } from 'lodash'; import { hasValue, isEmpty, isNotEmpty, isNotNull, isNotUndefined, isNull } from '../../empty.util'; import { DynamicQualdropModel } from './ds-dynamic-form-ui/models/ds-dynamic-qualdrop.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 { RowParser } from './parsers/row-parser'; @@ -150,7 +153,7 @@ export class FormBuilderService extends DynamicFormService { } if (this.isRelationGroup(controlModel)) { - const values = (controlModel as any).value; + const values = (controlModel as DynamicGroupModel).getGroupValue(); values.forEach((groupValue, groupIndex) => { const newGroupValue = Object.create({}); Object.keys(groupValue) diff --git a/src/app/shared/form/form.actions.ts b/src/app/shared/form/form.actions.ts index 7023d6bba1..3eb3fb2716 100644 --- a/src/app/shared/form/form.actions.ts +++ b/src/app/shared/form/form.actions.ts @@ -106,11 +106,12 @@ export class FormAddError implements Action { payload: { formId: string, fieldId: string, + fieldIndex: number, errorMessage: string, }; - constructor(formId: string, fieldId: string, errorMessage: string) { - this.payload = {formId, fieldId, errorMessage}; + constructor(formId: string, fieldId: string, fieldIndex: number, errorMessage: string) { + this.payload = {formId, fieldId, fieldIndex, errorMessage}; } } @@ -118,11 +119,12 @@ export class FormRemoveErrorAction implements Action { type = FormActionTypes.FORM_REMOVE_ERROR; payload: { formId: string, - fieldId: string + fieldId: string, + fieldIndex: number, }; - constructor(formId: string, fieldId: string) { - this.payload = {formId, fieldId}; + constructor(formId: string, fieldId: string, fieldIndex: number,) { + this.payload = {formId, fieldId, fieldIndex}; } } diff --git a/src/app/shared/form/form.component.ts b/src/app/shared/form/form.component.ts index bca87b9429..54a39a80fa 100644 --- a/src/app/shared/form/form.component.ts +++ b/src/app/shared/form/form.component.ts @@ -162,14 +162,15 @@ export class FormComponent implements OnDestroy, OnInit { const {formGroup, formModel} = this; 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) => { const {fieldId} = error; + const {fieldIndex} = error; let field: AbstractControl; 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 { - field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel); + field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel, fieldIndex); } if (field) { @@ -181,14 +182,15 @@ export class FormComponent implements OnDestroy, OnInit { }); 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) => { const {fieldId} = error; + const {fieldIndex} = error; let field: AbstractControl; 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 { - field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel); + field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel, fieldIndex); } if (field) { @@ -251,8 +253,9 @@ export class FormComponent implements OnDestroy, OnInit { } const control: FormControl = event.control; + const fieldIndex: number = (event.context && event.context.index) ? event.context.index : 0; if (control.valid) { - this.store.dispatch(new FormRemoveErrorAction(this.formId, event.model.id)); + this.store.dispatch(new FormRemoveErrorAction(this.formId, event.model.id, fieldIndex)); } } diff --git a/src/app/shared/form/form.reducer.spec.ts b/src/app/shared/form/form.reducer.spec.ts index ddd5f96ecd..01e3e6b1ba 100644 --- a/src/app/shared/form/form.reducer.spec.ts +++ b/src/app/shared/form/form.reducer.spec.ts @@ -1,9 +1,11 @@ -import { FormEntry, formReducer } from './form.reducer'; +import { formReducer } from './form.reducer'; import { FormAddError, - FormChangeAction, FormClearErrorsAction, + FormChangeAction, + FormClearErrorsAction, FormInitAction, - FormRemoveAction, FormRemoveErrorAction, + FormRemoveAction, + FormRemoveErrorAction, FormStatusChangeAction } from './form.actions'; @@ -165,15 +167,17 @@ describe('formReducer', () => { const expectedErrors = [ { fieldId: 'title', + fieldIndex: 0, message: 'Not valid' } ]; const formId = 'testForm'; const fieldId = 'title'; + const fieldIndex = 0; const message = 'Not valid'; - const action = new FormAddError(formId, fieldId, message); + const action = new FormAddError(formId, fieldId, fieldIndex, message); const newState = formReducer(initState, action); expect(newState.testForm.errors).toEqual(expectedErrors); @@ -192,10 +196,12 @@ describe('formReducer', () => { errors: [ { fieldId: 'author', + fieldIndex: 0, message: 'error.validation.required' }, { fieldId: 'title', + fieldIndex: 0, message: 'error.validation.required' } ] @@ -205,13 +211,16 @@ describe('formReducer', () => { const expectedErrors = [ { fieldId: 'title', + fieldIndex: 0, message: 'error.validation.required' } ]; 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); expect(newState.testForm.errors).toEqual(expectedErrors); @@ -252,6 +261,7 @@ describe('formReducer', () => { errors: [ { fieldId: 'author', + fieldIndex: 0, message: 'error.validation.required' } ] diff --git a/src/app/shared/form/form.reducer.ts b/src/app/shared/form/form.reducer.ts index 69f84978f7..1d44375c0d 100644 --- a/src/app/shared/form/form.reducer.ts +++ b/src/app/shared/form/form.reducer.ts @@ -14,6 +14,7 @@ import { isEqual, uniqWith } from 'lodash'; export interface FormError { message: string; fieldId: string; + fieldIndex: number; } export interface FormEntry { @@ -70,6 +71,7 @@ function addFormErrors(state: FormState, action: FormAddError) { if (hasValue(state[formId])) { const error: FormError = { fieldId: action.payload.fieldId, + fieldIndex: action.payload.fieldIndex, message: action.payload.errorMessage }; @@ -88,8 +90,9 @@ function addFormErrors(state: FormState, action: FormAddError) { function removeFormError(state: FormState, action: FormRemoveErrorAction) { const formId = action.payload.formId; const fieldId = action.payload.fieldId; + const fieldIndex = action.payload.fieldIndex; 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); newState[formId] = Object.assign({}, state[formId], {errors}); return newState;