diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.html index f26238cc1f..5614e23c4a 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.html @@ -127,8 +127,8 @@ [showWeekdays]="getAdditional('showWeekdays', true)" [showWeekNumbers]="getAdditional('showWeekNumbers', false)" [startDate]="model.focusedDate" + (dateSelect)="onValueChange($event)" (blur)="onBlur($event)" - (change)="onValueChange($event)" (focus)="onFocus($event)">
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts index cd6557b560..a38c35eb9c 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/ds-dynamic-form-control.component.ts @@ -12,7 +12,6 @@ import { import { FormGroup } from '@angular/forms'; import { DynamicDatePickerModel, - DynamicFormArrayGroupModel, DynamicFormControlComponent, DynamicFormControlEvent, DynamicFormControlModel, @@ -172,5 +171,4 @@ export class DsDynamicFormControlComponent extends DynamicFormControlComponent i this.onValueChange(event); } } - } diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html index 81733ff999..96ee0dd38e 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.html @@ -1,46 +1,46 @@
-
- -
+ -
- -
+ -
- -
+
diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts index 663e17c0b1..6d50d4375b 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/date-picker/date-picker.component.ts @@ -1,6 +1,7 @@ import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core'; import { FormGroup } from '@angular/forms'; import { DynamicDsDatePickerModel } from './date-picker.model'; +import { hasValue, isNotEmpty } from '../../../../../empty.util'; export const DS_DATE_PICKER_SEPARATOR = '-'; @@ -20,12 +21,10 @@ export class DsDatePickerComponent implements OnInit { // @Input() // maxDate; - @Output() - selected = new EventEmitter(); - @Output() - remove = new EventEmitter(); - @Output() - change = new EventEmitter(); + @Output() selected = new EventEmitter(); + @Output() remove = new EventEmitter(); + @Output() change = new EventEmitter(); + @Output() focus = new EventEmitter(); initialYear: number; initialMonth: number; @@ -48,9 +47,8 @@ export class DsDatePickerComponent implements OnInit { disabledMonth = true; disabledDay = true; - invalid = false; - ngOnInit() {// TODO Manage fields when not setted + ngOnInit() { const now = new Date(); this.initialYear = now.getFullYear(); this.initialMonth = now.getMonth() + 1; @@ -76,15 +74,6 @@ export class DsDatePickerComponent implements OnInit { this.maxYear = this.initialYear + 100; - // Invalid state for year - this.group.get(this.model.id).statusChanges.subscribe((state) => { - if (state === 'INVALID' || this.model.malformedDate) { - this.invalid = true; - } else { - this.invalid = false; - this.model.malformedDate = false; - } - }); } onChange(event) { @@ -157,8 +146,13 @@ export class DsDatePickerComponent implements OnInit { : this.day.toString(); value += DS_DATE_PICKER_SEPARATOR + dd; } + this.model.valueUpdates.next(value); - this.change.emit(event); + this.change.emit(value); + } + + onFocus(event) { + this.focus.emit(event); } getLastDay(date: Date) { diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.html index 916026a85b..c628eaf8e5 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/dynamic-group/dynamic-group.component.html @@ -18,10 +18,11 @@
+ [displaySubmit]="false" + (dfChange)="onChange($event)">
@@ -54,7 +55,11 @@
- +
{ + this.formCollapsed = (isNotEmpty(value) && !(value.length === 1 && isObjectEmpty(value[0]))) ? Observable.of(true) : Observable.of(false); + }); + this.formId = this.formService.getUniqueId(this.model.id); this.formModel = this.formBuilderService.modelFromConfiguration(config, this.model.scopeUUID, {}); - this.chips = new Chips(this.model.value, 'value', this.model.mandatoryField); + this.chips = new Chips(this.model.value, 'value', this.model.mandatoryField, this.EnvConfig.submission.metadata.icons); this.subs.push( this.chips.chipsItems .subscribe((subItems: any[]) => { @@ -118,20 +130,32 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit { return res; } + onChange(event: DynamicFormControlEvent) { + return + } + onChipSelected(event) { this.expandForm(); this.selectedChipItem = this.chips.getChipByIndex(event); this.formModel.forEach((row) => { const modelRow = row as DynamicFormGroupModel; modelRow.group.forEach((model: DynamicInputModel) => { - const value = this.selectedChipItem.item[model.name] === PLACEHOLDER_PARENT_METADATA ? null : this.selectedChipItem.item[model.name]; - if (model instanceof DynamicLookupModel) { - (model as DynamicLookupModel).valueUpdates.next(value); - } else if (model instanceof DynamicInputModel) { - model.valueUpdates.next(value); + const value = (this.selectedChipItem.item[model.name] === PLACEHOLDER_PARENT_METADATA + || this.selectedChipItem.item[model.name].value === PLACEHOLDER_PARENT_METADATA) + ? null + : this.selectedChipItem.item[model.name]; + if (value instanceof FormFieldMetadataValueObject || value instanceof AuthorityValueModel) { + model.valueUpdates.next(value.display); } else { - (model as any).value = value; + model.valueUpdates.next(value); } + // if (model instanceof DynamicLookupModel) { + // (model as DynamicLookupModel).valueUpdates.next(value); + // } else if (model instanceof DynamicInputModel) { + // model.valueUpdates.next(value); + // } else { + // (model as any).value = value; + // } }); }); diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts index a3baa3de88..91bd0275e7 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/list/dynamic-list.component.ts @@ -6,12 +6,11 @@ import { AuthorityService } from '../../../../../../core/integration/authority.s import { IntegrationSearchOptions } from '../../../../../../core/integration/models/integration-options.model'; import { hasValue, isNotEmpty } from '../../../../../empty.util'; import { DynamicListCheckboxGroupModel } from './dynamic-list-checkbox-group.model'; -import { ConfigData } from '../../../../../../core/config/config-data'; -import { ConfigAuthorityModel } from '../../../../../../core/shared/config/config-authority.model'; import { FormBuilderService } from '../../../form-builder.service'; import { DynamicCheckboxModel } from '@ng-dynamic-forms/core'; import { AuthorityValueModel } from '../../../../../../core/integration/models/authority-value.model'; import { DynamicListRadioGroupModel } from './dynamic-list-radio-group.model'; +import { IntegrationData } from '../../../../../../core/integration/integration-data'; export interface ListItem { id: string, @@ -26,7 +25,6 @@ export interface ListItem { templateUrl: './dynamic-list.component.html' }) -// TODO Fare questo componente da zero export class DsDynamicListComponent implements OnInit { @Input() bindId = true; @Input() group: FormGroup; @@ -91,13 +89,13 @@ export class DsDynamicListComponent implements OnInit { protected setOptionsFromAuthority() { if (this.model.authorityOptions.name && this.model.authorityOptions.name.length > 0) { const listGroup = this.group.controls[this.model.id] as FormGroup; - this.authorityService.getEntriesByName(this.searchOptions).subscribe((authorities: ConfigData) => { + this.authorityService.getEntriesByName(this.searchOptions).subscribe((authorities: IntegrationData) => { let groupCounter = 0; let itemsPerGroup = 0; let tempList: ListItem[] = []; - this.authorityList = authorities.payload as ConfigAuthorityModel[]; + this.authorityList = authorities.payload as AuthorityValueModel[]; // Make a list of available options (checkbox/radio) and split in groups of 'model.groupLength' - (authorities.payload as ConfigAuthorityModel[]).forEach((option, key) => { + (authorities.payload as AuthorityValueModel[]).forEach((option, key) => { const value = option.id || option.value; const checked: boolean = isNotEmpty(findKey( this.model.value, diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html index 972538efad..14f468b0f8 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.html @@ -1,7 +1,6 @@ -
+ (openChange)="openChange($event);">
@@ -19,26 +18,25 @@ [placeholder]="model.placeholder" [readonly]="model.readOnly" (change)="$event.preventDefault()" - (blur)="onBlurEvent($event); sdRef.close();" - (focus)="onFocusEvent($event); sdRef.close();" - (click)="$event.stopPropagation(); sdRef.close();" + (blur)="onBlurEvent($event); $event.stopPropagation(); sdRef.close();" + (focus)="onFocusEvent($event); $event.stopPropagation(); sdRef.close();" + (click)="$event.stopPropagation(); $event.stopPropagation(); sdRef.close();" (input)="onInput($event)">
- -
@@ -59,9 +57,9 @@ [placeholder]="model.placeholder | translate" [readonly]="model.readOnly" (change)="$event.preventDefault()" - (blur)="onBlurEvent($event); sdRef.close();" - (focus)="onFocusEvent($event); sdRef.close();" - (click)="$event.stopPropagation(); sdRef.close();" + (blur)="onBlurEvent($event); $event.stopPropagation(); sdRef.close();" + (focus)="onFocusEvent($event); $event.stopPropagation(); sdRef.close();" + (click)="$event.stopPropagation(); $event.stopPropagation(); sdRef.close();" (input)="onInput($event)">
@@ -78,24 +76,23 @@ [placeholder]="model.placeholder2 | translate" [readonly]="model.readOnly" (change)="$event.preventDefault()" - (blur)="onBlurEvent($event); sdRef.close();" - (focus)="onFocusEvent($event); sdRef.close();" + (blur)="onBlurEvent($event); $event.stopPropagation(); sdRef.close();" + (focus)="onFocusEvent($event); $event.stopPropagation(); sdRef.close();" (click)="$event.stopPropagation(); sdRef.close();" (input)="onInput($event)">
- -
@@ -115,11 +112,11 @@ diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss index a333fc881f..a697772020 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/lookup/dynamic-lookup.component.scss @@ -1,5 +1,9 @@ @import "../../../../../../../styles/variables"; +.dropdown-toggle::after { + display:none +} + /* enable absolute positioning */ .spinner-addon { position: relative; diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html index 1ea1b62cd0..aed4e16bca 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/scrollable-dropdown/dynamic-scrollable-dropdown.component.html @@ -30,11 +30,11 @@ (scrolled)="onScroll()" [scrollWindow]="false"> - + -

Loading...

+

{{'form.loading' | translate}}

diff --git a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts index a261eef8f7..1d31fc0968 100644 --- a/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts +++ b/src/app/shared/form/builder/ds-dynamic-form-ui/models/typeahead/dynamic-typeahead.component.ts @@ -30,6 +30,7 @@ export class DsDynamicTypeaheadComponent implements OnInit { searchFailed = false; hideSearchingWhenUnsubscribed = new Observable(() => () => this.changeSearchingStatus(false)); currentValue: any; + inputValue: any; formatter = (x: { display: string }) => { return (typeof x === 'object') ? x.display : x @@ -88,9 +89,8 @@ export class DsDynamicTypeaheadComponent implements OnInit { onInput(event) { if (!this.model.authorityOptions.closed && isNotEmpty(event.target.value)) { const valueObj = new FormFieldMetadataValueObject(event.target.value); - this.currentValue = valueObj; - this.model.valueUpdates.next(valueObj as any); - this.change.emit(valueObj); + this.inputValue = valueObj; + this.model.valueUpdates.next(this.inputValue); } if (event.data) { // this.group.markAsDirty(); @@ -98,6 +98,10 @@ export class DsDynamicTypeaheadComponent implements OnInit { } onBlurEvent(event: Event) { + if (!this.model.authorityOptions.closed && isNotEmpty(this.inputValue)) { + this.change.emit(this.inputValue); + this.inputValue = null; + } this.blur.emit(event); } @@ -114,6 +118,7 @@ export class DsDynamicTypeaheadComponent implements OnInit { } onSelectItem(event: NgbTypeaheadSelectItemEvent) { + this.inputValue = null; this.currentValue = event.item; this.model.valueUpdates.next(event.item); this.change.emit(event.item); diff --git a/src/app/shared/form/builder/form-builder.service.ts b/src/app/shared/form/builder/form-builder.service.ts index 78509f76de..2b0cddaaa4 100644 --- a/src/app/shared/form/builder/form-builder.service.ts +++ b/src/app/shared/form/builder/form-builder.service.ts @@ -10,20 +10,26 @@ import { DynamicPathable, JSONUtils, } from '@ng-dynamic-forms/core'; -import { mergeWith } from 'lodash'; +import { mergeWith, isObject } from 'lodash'; import { isEmpty, isNotEmpty, isNotNull, isNotUndefined, isNull } from '../../empty.util'; import { DynamicComboboxModel } from './ds-dynamic-form-ui/models/ds-dynamic-combobox.model'; import { SubmissionFormsModel } from '../../../core/shared/config/config-submission-forms.model'; import { DynamicConcatModel } from './ds-dynamic-form-ui/models/ds-dynamic-concat.model'; import { DynamicListCheckboxGroupModel } from './ds-dynamic-form-ui/models/list/dynamic-list-checkbox-group.model'; -import { DynamicGroupModel } from './ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; -import { DynamicTagModel } from './ds-dynamic-form-ui/models/tag/dynamic-tag.model'; +import { + DYNAMIC_FORM_CONTROL_TYPE_RELATION, + DynamicGroupModel +} from './ds-dynamic-form-ui/models/dynamic-group/dynamic-group.model'; +import { DYNAMIC_FORM_CONTROL_TYPE_TAG, DynamicTagModel } from './ds-dynamic-form-ui/models/tag/dynamic-tag.model'; import { DynamicListRadioGroupModel } from './ds-dynamic-form-ui/models/list/dynamic-list-radio-group.model'; import { RowParser } from './parsers/row-parser'; import { DynamicRowArrayModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-array-model'; import { DynamicRowGroupModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-group-model'; +import { DsDynamicInputModel } from './ds-dynamic-form-ui/models/ds-dynamic-input.model'; +import { FormFieldMetadataValueObject } from './models/form-field-metadata-value.model'; +import { AuthorityValueModel } from '../../../core/integration/models/authority-value.model'; @Injectable() export class FormBuilderService extends DynamicFormService { @@ -95,11 +101,25 @@ export class FormBuilderService extends DynamicFormService { } }; - const iterateControlModels = (findGroupModel: DynamicFormControlModel[]): void => { + const normalizeValue = (controlModel, controlValue, controlModelIndex) => { + const controlLanguage = (controlModel as DsDynamicInputModel).hasLanguages ? (controlModel as DsDynamicInputModel).language : null; + if (((isObject(controlValue) && controlValue.id) || controlValue instanceof AuthorityValueModel)) { + return new FormFieldMetadataValueObject(controlValue.value, controlLanguage, controlValue.id, controlValue.display, controlModelIndex); + } else if (!(controlValue instanceof FormFieldMetadataValueObject)) { + return new FormFieldMetadataValueObject(controlValue, controlLanguage, null, null, controlModelIndex); + } else { + const place = controlModelIndex || controlValue.place; + return Object.assign(new FormFieldMetadataValueObject(), controlValue, {place}); + } + }; + + const iterateControlModels = (findGroupModel: DynamicFormControlModel[], controlModelIndex: number = 0): void => { let iterateResult = Object.create({}); // Iterate over all group's controls for (const controlModel of findGroupModel) { + /* tslint:disable-next-line:no-shadowed-variable */ + // for (const {controlModel, controlModelIndex} of findGroupModel.map((controlModel, controlModelIndex) => ({ controlModel, controlModelIndex }))) { if (controlModel instanceof DynamicRowGroupModel && !this.isCustomGroup(controlModel)) { iterateResult = mergeWith(iterateResult, iterateControlModels((controlModel as DynamicFormGroupModel).group), customizer); @@ -113,7 +133,7 @@ export class FormBuilderService extends DynamicFormService { if (controlModel instanceof DynamicRowArrayModel) { for (const arrayItemModel of controlModel.groups) { - iterateResult = mergeWith(iterateResult, iterateControlModels(arrayItemModel.group), customizer); + iterateResult = mergeWith(iterateResult, iterateControlModels(arrayItemModel.group, arrayItemModel.index), customizer); } continue; } @@ -121,7 +141,7 @@ export class FormBuilderService extends DynamicFormService { if (controlModel instanceof DynamicFormArrayModel) { iterateResult[controlModel.name] = []; for (const arrayItemModel of controlModel.groups) { - iterateResult[controlModel.name].push(iterateControlModels(arrayItemModel.group)); + iterateResult[controlModel.name].push(iterateControlModels(arrayItemModel.group, arrayItemModel.index)); } continue; } @@ -135,12 +155,37 @@ export class FormBuilderService extends DynamicFormService { controlId = controlModel.name; } - const controlValue = isNotUndefined((controlModel as any).value) ? (controlModel as any).value : null; - if (controlId && iterateResult.hasOwnProperty(controlId) && isNotNull(iterateResult[controlId])) { - iterateResult[controlId].push(controlValue); - } else { - iterateResult[controlId] = isNotEmpty(controlValue) ? (Array.isArray(controlValue) ? controlValue : [controlValue]) : null; + if (controlModel instanceof DynamicGroupModel) { + const values = (controlModel as any).value; + values.forEach((groupValue, groupIndex) => { + const newGroupValue = Object.create({}); + Object.keys(groupValue) + .forEach((key) => { + const normValue = normalizeValue(controlModel, groupValue[key], groupIndex); + if (iterateResult.hasOwnProperty(key)) { + iterateResult[key].push(normValue); + } else { + iterateResult[key] = [normValue]; + } + // newGroupValue[key] = normalizeValue(controlModel, groupValue[key], groupIndex); + }); + // controlArrayValue.push(newGroupValue); + }) + } else if (isNotUndefined((controlModel as any).value) && isNotEmpty((controlModel as any).value)) { + const controlArrayValue = []; + // Normalize control value as an array of FormFieldMetadataValueObject + const values = Array.isArray((controlModel as any).value) ? (controlModel as any).value : [(controlModel as any).value]; + values.forEach((controlValue) => { + controlArrayValue.push(normalizeValue(controlModel, controlValue, controlModelIndex)) + }); + + if (controlId && iterateResult.hasOwnProperty(controlId) && isNotNull(iterateResult[controlId])) { + iterateResult[controlId] = iterateResult[controlId].concat(controlArrayValue); + } else { + iterateResult[controlId] = isNotEmpty(controlArrayValue) ? controlArrayValue : null; + } } + } return iterateResult; @@ -182,16 +227,29 @@ export class FormBuilderService extends DynamicFormService { || model.parent instanceof DynamicGroupModel); } + isComboboxGroup(model: DynamicFormControlModel) { + return model && model instanceof DynamicComboboxModel; + } + isCustomGroup(model: DynamicFormControlModel) { return model && (model instanceof DynamicConcatModel || model instanceof DynamicComboboxModel - || model instanceof DynamicListCheckboxGroupModel + || this.isListGroup(model)); + } + + isListGroup(model: DynamicFormControlModel) { + return model && + (model instanceof DynamicListCheckboxGroupModel || model instanceof DynamicListRadioGroupModel); } isModelInAuthorityGroup(model: DynamicFormControlModel) { - return (model instanceof DynamicListCheckboxGroupModel || model instanceof DynamicTagModel); + return model && (this.isListGroup(model) || model.type === DYNAMIC_FORM_CONTROL_TYPE_TAG); + } + + isRelationGroup(model: DynamicFormControlModel) { + return model && model.type === DYNAMIC_FORM_CONTROL_TYPE_RELATION; } getFormControlById(id: string, formGroup: FormGroup, groupModel: DynamicFormControlModel[], index = 0) { diff --git a/src/app/shared/form/builder/models/form-field-metadata-value.model.ts b/src/app/shared/form/builder/models/form-field-metadata-value.model.ts index 7379d62de6..ebcdc9264c 100644 --- a/src/app/shared/form/builder/models/form-field-metadata-value.model.ts +++ b/src/app/shared/form/builder/models/form-field-metadata-value.model.ts @@ -2,7 +2,7 @@ import { isNotEmpty } from '../../../empty.util'; export class FormFieldMetadataValueObject { metadata?: string; - value: string; + value: any; display: string; language: any; authority: string; @@ -11,14 +11,14 @@ export class FormFieldMetadataValueObject { closed: boolean; label: string; - constructor(value: string, + constructor(value: any = null, language: any = null, authority: string = null, display: string = null, + place: number = 0, confidence: number = -1, - place: number = -1, metadata: string = null) { - this.value = value; + this.value = isNotNull(value) ? ((typeof value === 'string') ? value.trim() : value) : null; this.language = language; this.authority = authority; this.display = display || value; @@ -39,4 +39,8 @@ export class FormFieldMetadataValueObject { hasAuthority(): boolean { return isNotEmpty(this.authority); } + + hasValue(): boolean { + return isNotEmpty(this.value); + } } diff --git a/src/app/shared/form/builder/parsers/date-field-parser.ts b/src/app/shared/form/builder/parsers/date-field-parser.ts index 57e4a4cacb..6ad244f298 100644 --- a/src/app/shared/form/builder/parsers/date-field-parser.ts +++ b/src/app/shared/form/builder/parsers/date-field-parser.ts @@ -4,20 +4,19 @@ import { FormFieldModel } from '../models/form-field.model'; import { DynamicDsDatePickerModel } from '../ds-dynamic-form-ui/models/date-picker/date-picker.model'; import { isNotEmpty } from '../../../empty.util'; import { DS_DATE_PICKER_SEPARATOR } from '../ds-dynamic-form-ui/models/date-picker/date-picker.component'; +import { FormFieldMetadataValueObject } from '../models/form-field-metadata-value.model'; export class DateFieldParser extends FieldParser { - public modelFactory(): any { + public modelFactory(fieldValue: FormFieldMetadataValueObject): any { const inputDateModelConfig: DynamicDatePickerModelConfig = this.initModel(); inputDateModelConfig.toggleIcon = 'fa fa-calendar'; - - const dateModel = new DynamicDsDatePickerModel(inputDateModelConfig); - + this.setValues(inputDateModelConfig as any, fieldValue); // Init Data and validity check - if (isNotEmpty(this.getInitFieldValue())) { + if (isNotEmpty(inputDateModelConfig.value)) { let malformedData = false; - const value = this.getInitFieldValue().toString(); + const value = inputDateModelConfig.value.toString(); if (value.length >= 4) { const valuesArray = value.split(DS_DATE_PICKER_SEPARATOR); if (valuesArray.length < 4) { @@ -29,12 +28,8 @@ export class DateFieldParser extends FieldParser { } } - if (!malformedData) { - dateModel.valueUpdates.next(this.getInitFieldValue()); - } else { + if (malformedData) { // TODO Set error message - dateModel.malformedDate = true; - // TODO // const errorMessage = 'The stored date is not compliant'; // dateModel.validators = Object.assign({}, dateModel.validators, {malformedDate: null}); // dateModel.errorMessages = Object.assign({}, dateModel.errorMessages, {malformedDate: errorMessage}); @@ -44,6 +39,7 @@ export class DateFieldParser extends FieldParser { } } + const dateModel = new DynamicDsDatePickerModel(inputDateModelConfig); return dateModel; } } diff --git a/src/app/shared/form/builder/parsers/field-parser.ts b/src/app/shared/form/builder/parsers/field-parser.ts index 29a133171d..9845f1772d 100644 --- a/src/app/shared/form/builder/parsers/field-parser.ts +++ b/src/app/shared/form/builder/parsers/field-parser.ts @@ -118,9 +118,9 @@ export abstract class FieldParser { const values: FormFieldMetadataValueObject[] = []; fieldIds.forEach((id) => { if (this.initFormValues.hasOwnProperty(id)) { - const valueObj: FormFieldMetadataValueObject = Object.create({}); + const valueObj: FormFieldMetadataValueObject = Object.assign(new FormFieldMetadataValueObject(), this.initFormValues[id][innerIndex]); valueObj.metadata = id; - valueObj.value = this.initFormValues[id][innerIndex]; + // valueObj.value = this.initFormValues[id][innerIndex]; values.push(valueObj); } }); @@ -243,16 +243,21 @@ export abstract class FieldParser { if (typeof fieldValue === 'object') { modelConfig.language = fieldValue.language; - if (hasValue(fieldValue.language)) { - // Instance of FormFieldLanguageValueObject - modelConfig.value = fieldValue.value; - } else if (hasValue(fieldValue.metadata)) { - // Is a combobox field's value - modelConfig.value = fieldValue.value; - } else { - // Instance of FormFieldMetadataValueObject + if (forceValueAsObj) { modelConfig.value = fieldValue; + } else { + modelConfig.value = fieldValue.value; } + // if (hasValue(fieldValue.language)) { + // // Instance of FormFieldLanguageValueObject + // modelConfig.value = fieldValue.value; + // } else if (hasValue(fieldValue.metadata)) { + // // Is a combobox field's value + // modelConfig.value = fieldValue.value; + // } else { + // // Instance of FormFieldMetadataValueObject + // modelConfig.value = fieldValue; + // } } else { if (forceValueAsObj) { // If value isn't an instance of FormFieldMetadataValueObject instantiate it diff --git a/src/app/shared/form/builder/parsers/onebox-field-parser.ts b/src/app/shared/form/builder/parsers/onebox-field-parser.ts index 3b1bfc935c..c5a4f50e0c 100644 --- a/src/app/shared/form/builder/parsers/onebox-field-parser.ts +++ b/src/app/shared/form/builder/parsers/onebox-field-parser.ts @@ -68,7 +68,6 @@ export class OneboxFieldParser extends FieldParser { if (isNotEmpty(fieldValue)) { selectModelConfig.value = fieldValue.metadata; } - selectModelConfig.disabled = true; inputSelectGroup.group.push(new DynamicSelectModel(selectModelConfig, clsSelect)); const inputModelConfig: DsDynamicInputModelConfig = this.initModel(newId + COMBOBOX_VALUE_SUFFIX, true, true); diff --git a/src/app/shared/form/form.actions.ts b/src/app/shared/form/form.actions.ts index b1d5f2b3e3..7023d6bba1 100644 --- a/src/app/shared/form/form.actions.ts +++ b/src/app/shared/form/form.actions.ts @@ -114,6 +114,29 @@ export class FormAddError implements Action { } } +export class FormRemoveErrorAction implements Action { + type = FormActionTypes.FORM_REMOVE_ERROR; + payload: { + formId: string, + fieldId: string + }; + + constructor(formId: string, fieldId: string) { + this.payload = {formId, fieldId}; + } +} + +export class FormClearErrorsAction implements Action { + type = FormActionTypes.FORM_CLEAR_ERRORS; + payload: { + formId: string + }; + + constructor(formId: string) { + this.payload = {formId}; + } +} + /* tslint:enable:max-classes-per-file */ /** @@ -125,3 +148,5 @@ export type FormAction = FormInitAction | FormRemoveAction | FormStatusChangeAction | FormAddError + | FormClearErrorsAction + | FormRemoveErrorAction diff --git a/src/app/shared/form/form.component.ts b/src/app/shared/form/form.component.ts index 99712bde9c..981aed083e 100644 --- a/src/app/shared/form/form.component.ts +++ b/src/app/shared/form/form.component.ts @@ -10,7 +10,13 @@ import { import { Store } from '@ngrx/store'; import { AppState } from '../../app.reducer'; -import { FormChangeAction, FormInitAction, FormRemoveAction, FormStatusChangeAction } from './form.actions'; +import { + FormChangeAction, + FormInitAction, + FormRemoveAction, + FormRemoveErrorAction, + FormStatusChangeAction +} from './form.actions'; import { FormBuilderService } from './builder/form-builder.service'; import { Observable } from 'rxjs/Observable'; import { Subscription } from 'rxjs/Subscription'; @@ -144,7 +150,7 @@ export class FormComponent implements OnDestroy, OnInit { .filter((formState: FormEntry) => !!formState && !isEmpty(formState.errors)) .map((formState) => formState.errors) .distinctUntilChanged() - .delay(100) // this terrible delay is here to prevent the detection change error + // .delay(100) // this terrible delay is here to prevent the detection change error .subscribe((errors: FormError[]) => { const {formGroup, formModel} = this; @@ -172,10 +178,10 @@ export class FormComponent implements OnDestroy, OnInit { * Method provided by Angular. Invoked when the instance is destroyed */ ngOnDestroy() { - this.store.dispatch(new FormRemoveAction(this.formId)); this.subs .filter((sub) => hasValue(sub)) .forEach((sub) => sub.unsubscribe()); + this.store.dispatch(new FormRemoveAction(this.formId)); } /** @@ -206,7 +212,6 @@ export class FormComponent implements OnDestroy, OnInit { } onChange(event) { - console.log(event, this.formGroup); const action: FormChangeAction = new FormChangeAction(this.formId, this.formBuilderService.getValueFromModel(this.formModel)); this.store.dispatch(action); @@ -215,7 +220,10 @@ export class FormComponent implements OnDestroy, OnInit { this.change.emit(event); const control: FormControl = event.control; - control.setErrors(null); + // control.setErrors(null); + if (control.valid) { + this.store.dispatch(new FormRemoveErrorAction(this.formId, event.model.id)); + } } /** diff --git a/src/app/shared/form/form.reducers.ts b/src/app/shared/form/form.reducers.ts index d06db331eb..c65f2405ec 100644 --- a/src/app/shared/form/form.reducers.ts +++ b/src/app/shared/form/form.reducers.ts @@ -1,9 +1,15 @@ import { - FormAction, FormActionTypes, FormAddError, FormChangeAction, FormInitAction, FormRemoveAction, + FormAction, + FormActionTypes, + FormAddError, + FormChangeAction, FormClearErrorsAction, + FormInitAction, + FormRemoveAction, + FormRemoveErrorAction, FormStatusChangeAction } from './form.actions'; import { hasValue } from '../empty.util'; -import { uniqWith, isEqual } from 'lodash'; +import { isEqual, uniqWith } from 'lodash'; export interface FormError { message: string; @@ -45,6 +51,14 @@ export function formReducer(state = initialState, action: FormAction): FormState return addFormErrors(state, action as FormAddError) } + case FormActionTypes.FORM_REMOVE_ERROR: { + return removeFormError(state, action as FormRemoveErrorAction) + } + + case FormActionTypes.FORM_CLEAR_ERRORS: { + return clearsFormErrors(state, action as FormClearErrorsAction) + } + default: { return state; } @@ -60,7 +74,7 @@ function addFormErrors(state: FormState, action: FormAddError) { }; return Object.assign({}, state, { - [ formId ]: { + [formId]: { data: state[formId].data, valid: state[formId].valid, errors: state[formId].errors ? uniqWith(state[formId].errors.concat(error), isEqual) : [].concat(error), @@ -71,6 +85,31 @@ function addFormErrors(state: FormState, action: FormAddError) { } } +function removeFormError(state: FormState, action: FormRemoveErrorAction) { + const formId = action.payload.formId; + const fieldId = action.payload.fieldId; + if (hasValue(state[formId])) { + const errors = state[formId].errors.filter((error) => error.fieldId !== fieldId); + const newState = Object.assign({}, state); + newState[formId] = Object.assign({}, state[formId], {errors}); + return newState; + } else { + return state; + } +} + +function clearsFormErrors(state: FormState, action: FormClearErrorsAction) { + const formId = action.payload.formId; + if (hasValue(state[formId])) { + const errors = []; + const newState = Object.assign({}, state); + newState[formId] = Object.assign({}, state[formId], {errors}); + return newState; + } else { + return state; + } +} + /** * Init form state. * @@ -82,22 +121,18 @@ function addFormErrors(state: FormState, action: FormAddError) { * the new state, with the form initialized. */ function initForm(state: FormState, action: FormInitAction): FormState { - if (!hasValue(state[ action.payload.formId ])) { + const formState = { + data: action.payload.formData, + valid: action.payload.valid, + errors: [] + }; + if (!hasValue(state[action.payload.formId])) { return Object.assign({}, state, { - [ action.payload.formId ]: { - data: action.payload.formData, - valid: action.payload.valid, - errors: [] - } + [action.payload.formId]: formState }); } else { const newState = Object.assign({}, state); - newState[ action.payload.formId ] = Object.assign({}, newState[ action.payload.formId ], { - data: action.payload.formData, - valid: action.payload.valid, - errors: [] - } - ); + newState[action.payload.formId] = Object.assign({}, newState[action.payload.formId], formState); return newState; } } @@ -113,18 +148,18 @@ function initForm(state: FormState, action: FormInitAction): FormState { * the new state, with the data changed. */ function changeDataForm(state: FormState, action: FormChangeAction): FormState { - if (!hasValue(state[ action.payload.formId ])) { + if (!hasValue(state[action.payload.formId])) { return Object.assign({}, state, { - [ action.payload.formId ]: { + [action.payload.formId]: { data: action.payload.formData, - valid: state[ action.payload.formId ].valid + valid: state[action.payload.formId].valid } }); } else { const newState = Object.assign({}, state); - newState[ action.payload.formId ] = Object.assign({}, newState[ action.payload.formId ], { + newState[action.payload.formId] = Object.assign({}, newState[action.payload.formId], { data: action.payload.formData, - valid: state[ action.payload.formId ].valid + valid: state[action.payload.formId].valid } ); return newState; @@ -142,17 +177,17 @@ function changeDataForm(state: FormState, action: FormChangeAction): FormState { * the new state, with the status changed. */ function changeStatusForm(state: FormState, action: FormStatusChangeAction): FormState { - if (!hasValue(state[ action.payload.formId ])) { + if (!hasValue(state[action.payload.formId])) { return Object.assign({}, state, { - [ action.payload.formId ]: { - data: state[ action.payload.formId ].data, + [action.payload.formId]: { + data: state[action.payload.formId].data, valid: action.payload.valid } }); } else { const newState = Object.assign({}, state); - newState[ action.payload.formId ] = Object.assign({}, newState[ action.payload.formId ], { - data: state[ action.payload.formId ].data, + newState[action.payload.formId] = Object.assign({}, newState[action.payload.formId], { + data: state[action.payload.formId].data, valid: action.payload.valid } ); @@ -171,9 +206,9 @@ function changeStatusForm(state: FormState, action: FormStatusChangeAction): For * the new state, with the form initialized. */ function removeForm(state: FormState, action: FormRemoveAction): FormState { - if (hasValue(state[ action.payload.formId ])) { + if (hasValue(state[action.payload.formId])) { const newState = Object.assign({}, state); - delete newState[ action.payload.formId ]; + delete newState[action.payload.formId]; return newState; } else { return state; diff --git a/src/app/shared/form/form.service.ts b/src/app/shared/form/form.service.ts index 2adef27179..f890d90012 100644 --- a/src/app/shared/form/form.service.ts +++ b/src/app/shared/form/form.service.ts @@ -84,7 +84,7 @@ export class FormService { error[errorKey] = message; // assign message - // if form control model has errorMessages object, create it + // if form control model has not errorMessages object, create it if (!model.errorMessages) { model.errorMessages = {}; } diff --git a/src/app/shared/number-picker/number-picker.component.html b/src/app/shared/number-picker/number-picker.component.html index 5eb45a0bfb..55e0c39078 100644 --- a/src/app/shared/number-picker/number-picker.component.html +++ b/src/app/shared/number-picker/number-picker.component.html @@ -1,7 +1,8 @@ -
+