updated with latest changes

This commit is contained in:
Giuseppe Digilio
2018-06-13 11:28:11 +02:00
parent 98f79a7f67
commit 6b8330fee1
12 changed files with 150 additions and 92 deletions

View File

@@ -288,6 +288,7 @@
<ds-dynamic-group [model]="model"
[formId]="formId"
[group]="group"
[showErrorMessages]="showErrorMessages"
(blur)="onBlur($event)"
(change)="onValueChange($event)"
(focus)="onFocus($event)"></ds-dynamic-group>

View File

@@ -10,6 +10,7 @@
[value]="year"
[invalid]="showErrorMessages"
[placeholder]='yearPlaceholder'
(blur)="onBlur($event)"
(change)="onChange($event)"
(focus)="onFocus($event)"
></ds-number-picker>
@@ -24,6 +25,7 @@
[value]="month"
[placeholder]="monthPlaceholder"
[disabled]="!year || model.disabled"
(blur)="onBlur($event)"
(change)="onChange($event)"
(focus)="onFocus($event)"
></ds-number-picker>
@@ -38,6 +40,7 @@
[value]="day"
[placeholder]="dayPlaceholder"
[disabled]="!month || model.disabled"
(blur)="onBlur($event)"
(change)="onChange($event)"
(focus)="onFocus($event)"
></ds-number-picker>

View File

@@ -1,5 +1,5 @@
import { Component, EventEmitter, Inject, Input, OnInit, Output } from '@angular/core';
import { FormGroup } from '@angular/forms';
import { FormControl, FormGroup } from '@angular/forms';
import { DynamicDsDatePickerModel } from './date-picker.model';
import { hasValue, isNotEmpty } from '../../../../../empty.util';
@@ -23,6 +23,7 @@ export class DsDatePickerComponent implements OnInit {
@Output() selected = new EventEmitter<number>();
@Output() remove = new EventEmitter<number>();
@Output() blur = new EventEmitter<any>();
@Output() change = new EventEmitter<any>();
@Output() focus = new EventEmitter<any>();
@@ -76,6 +77,10 @@ export class DsDatePickerComponent implements OnInit {
}
onBlur(event) {
this.blur.emit();
}
onChange(event) {
// update year-month-day
switch (event.field) {

View File

@@ -15,14 +15,16 @@
(click)="expandForm()"></span>
</a>
<div class="pt-2" [ngClass]="{'border-top': !invalid, 'border border-danger': invalid}">
<div class="pt-2" [ngClass]="{'border-top': !showErrorMessages, 'border border-danger': showErrorMessages}">
<div *ngIf="!(formCollapsed | async)" class="pl-2 row" @shrinkInOut>
<ds-form #formRef="formComponent"
class="col-sm-12 col-md-8 col-lg-9 col-xl-10 pl-0"
[formId]="formId"
[formModel]="formModel"
[displaySubmit]="false"
(dfChange)="onChange($event)"></ds-form>
[emitChange]="false"
(dfBlur)="onBlur($event)"
(dfFocus)="onFocus($event)"></ds-form>
<div *ngIf="!(formCollapsed | async)" class="col p-0 m-0 d-flex justify-content-center align-items-center">

View File

@@ -11,12 +11,7 @@ import {
} from '@angular/core';
import { Observable } from 'rxjs/Observable';
import {
DynamicFormControlEvent,
DynamicFormControlModel,
DynamicFormGroupModel,
DynamicInputModel
} from '@ng-dynamic-forms/core';
import { DynamicFormControlModel, DynamicFormGroupModel, DynamicInputModel } from '@ng-dynamic-forms/core';
import { isEqual } from 'lodash';
import { DynamicGroupModel, PLACEHOLDER_PARENT_METADATA } from './dynamic-group.model';
@@ -25,7 +20,6 @@ import { SubmissionFormsModel } from '../../../../../../core/shared/config/confi
import { FormService } from '../../../../form.service';
import { FormComponent } from '../../../../form.component';
import { Chips } from '../../../../../chips/models/chips.model';
import { DynamicLookupModel } from '../lookup/dynamic-lookup.model';
import { hasValue, isEmpty, isNotEmpty } from '../../../../../empty.util';
import { shrinkInOut } from '../../../../../animations/shrink';
import { ChipsItem } from '../../../../../chips/models/chips-item.model';
@@ -48,6 +42,7 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit {
@Input() formId: string;
@Input() group: FormGroup;
@Input() model: DynamicGroupModel;
@Input() showErrorMessages = false;
@Output() blur: EventEmitter<any> = new EventEmitter<any>();
@Output() change: EventEmitter<any> = new EventEmitter<any>();
@@ -57,7 +52,6 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit {
public formCollapsed = Observable.of(false);
public formModel: DynamicFormControlModel[];
public editMode = false;
public invalid = false;
private selectedChipItem: ChipsItem;
private subs: Subscription[] = [];
@@ -72,7 +66,7 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit {
ngOnInit() {
const config = {rows: this.model.formConfiguration} as SubmissionFormsModel;
if (isNotEmpty(this.model.value)) {
if (!this.model.isEmpty()) {
this.formCollapsed = Observable.of(true);
}
this.model.valueUpdates.subscribe((value: any[]) => {
@@ -80,38 +74,22 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit {
});
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.formModel = this.formBuilderService.modelFromConfiguration(config, this.model.scopeUUID, {}, this.model.submissionScope, this.model.readOnly);
const initChipsValue = this.model.isEmpty() ? [] : this.model.value;
this.chips = new Chips(initChipsValue, 'value', this.model.mandatoryField);
this.subs.push(
this.chips.chipsItems
.subscribe((subItems: any[]) => {
const items = this.chips.getChipsItems();
// Does not emit change if model value is equal to the current value
if (!isEqual(items, this.model.value)) {
if (isEmpty(items)) {
// If items is empty, last element has been removed
// so emit an empty value that allows to dispatch
// a remove JSON PATCH operation
const emptyItem = Object.create({});
Object.keys(this.model.value[0])
.forEach((key) => {
emptyItem[key] = null;
});
items.push(emptyItem);
// if ((isNotEmpty(items) && !this.model.isEmpty()) || (isEmpty(items) && !this.model.isEmpty())) {
if (!(isEmpty(items) && this.model.isEmpty())) {
this.model.valueUpdates.next(items);
this.change.emit();
}
this.model.valueUpdates.next(items);
this.change.emit();
}
}),
// Invalid state for year
this.group.get(this.model.id).statusChanges.subscribe((state) => {
if (state === 'INVALID') {
this.invalid = true;
} else {
this.invalid = false;
}
})
)
}
@@ -130,8 +108,8 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit {
return res;
}
onChange(event: DynamicFormControlEvent) {
return
onBlur(event) {
this.blur.emit();
}
onChipSelected(event) {
@@ -142,26 +120,23 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit {
modelRow.group.forEach((model: DynamicInputModel) => {
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];
? null
: this.selectedChipItem.item[model.name];
if (value instanceof FormFieldMetadataValueObject || value instanceof AuthorityValueModel) {
model.valueUpdates.next(value.display);
} else {
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;
// }
});
});
this.editMode = true;
}
onFocus(event) {
this.focus.emit(event);
}
collapseForm() {
this.formCollapsed = Observable.of(true);
this.clear();
@@ -178,7 +153,9 @@ export class DsDynamicGroupComponent implements OnDestroy, OnInit {
this.editMode = false;
}
this.resetForm();
// this.change.emit(event);
if (!this.model.isEmpty()) {
this.formCollapsed = Observable.of(true);
}
}
save() {

View File

@@ -1,6 +1,8 @@
import { DynamicFormControlLayout, serializable } from '@ng-dynamic-forms/core';
import { FormRowModel } from '../../../../../../core/shared/config/config-submission-forms.model';
import { DsDynamicInputModel, DsDynamicInputModelConfig } from '../ds-dynamic-input.model';
import { AuthorityValueModel } from '../../../../../../core/integration/models/authority-value.model';
import { isEmpty, isNull } from '../../../../../empty.util';
export const DYNAMIC_FORM_CONTROL_TYPE_RELATION = 'RELATION';
export const PLACEHOLDER_PARENT_METADATA = '#PLACEHOLDER_PARENT_METADATA_VALUE#';
@@ -14,6 +16,7 @@ export interface DynamicGroupModelConfig extends DsDynamicInputModelConfig {
name: string,
relationFields: string[],
scopeUUID: string,
submissionScope: string;
value?: any;
}
@@ -25,7 +28,8 @@ export class DynamicGroupModel extends DsDynamicInputModel {
@serializable() mandatoryField: string;
@serializable() relationFields: string[];
@serializable() scopeUUID: string;
@serializable() value: any[];
@serializable() submissionScope: string;
@serializable() _value: any[];
@serializable() readonly type: string = DYNAMIC_FORM_CONTROL_TYPE_RELATION;
constructor(config: DynamicGroupModelConfig, layout?: DynamicFormControlLayout) {
@@ -35,7 +39,32 @@ export class DynamicGroupModel extends DsDynamicInputModel {
this.mandatoryField = config.mandatoryField;
this.relationFields = config.relationFields;
this.scopeUUID = config.scopeUUID;
this.submissionScope = config.submissionScope;
const value = config.value || [];
this.valueUpdates.next(value)
this.valueUpdates.next(value);
}
get value() {
if (isEmpty(this._value)) {
// If items is empty, last element has been removed
// so emit an empty value that allows to dispatch
// a remove JSON PATCH operation
const emptyItem = Object.create({});
emptyItem[this.mandatoryField] = null;
this.relationFields
.forEach((field) => {
emptyItem[field] = null;
});
return [emptyItem];
}
return this._value
}
set value(value) {
this._value = value;
}
isEmpty() {
return (this.value.length === 1 && isNull(this.value[0][this.mandatoryField]));
}
}

View File

@@ -162,12 +162,13 @@ export class FormBuilderService extends DynamicFormService {
Object.keys(groupValue)
.forEach((key) => {
const normValue = normalizeValue(controlModel, groupValue[key], groupIndex);
if (iterateResult.hasOwnProperty(key)) {
iterateResult[key].push(normValue);
} else {
iterateResult[key] = [normValue];
if (normValue.hasValue()) {
if (iterateResult.hasOwnProperty(key)) {
iterateResult[key].push(normValue);
} else {
iterateResult[key] = [normValue];
}
}
// newGroupValue[key] = normalizeValue(controlModel, groupValue[key], groupIndex);
});
// controlArrayValue.push(newGroupValue);
})

View File

@@ -13,7 +13,8 @@ export class GroupFieldParser extends FieldParser {
constructor(protected configData: FormFieldModel,
protected initFormValues,
protected readOnly: boolean,
protected authorityUuid: string) {
protected submissionScope: string,
protected authorityUuid: string,) {
super(configData, initFormValues, readOnly);
}
@@ -21,6 +22,7 @@ export class GroupFieldParser extends FieldParser {
const modelConfiguration: DynamicGroupModelConfig = this.initModel();
modelConfiguration.scopeUUID = this.authorityUuid;
modelConfiguration.submissionScope = this.submissionScope;
if (this.configData && this.configData.rows && this.configData.rows.length > 0) {
modelConfiguration.formConfiguration = this.configData.rows;
modelConfiguration.relationFields = [];

View File

@@ -90,7 +90,7 @@ export class RowParser {
break;
case 'group':
fieldModel = new GroupFieldParser(fieldData, this.initFormValues, this.readOnly, this.authorityOptions.uuid).parse();
fieldModel = new GroupFieldParser(fieldData, this.initFormValues, this.readOnly, this.submissionScope, this.authorityOptions.uuid).parse();
break;
case 'twobox':

View File

@@ -6,6 +6,7 @@
[formGroup]="formGroup"
[formModel]="formModel"
[formLayout]="formLayout"
(change)="$event.stopPropagation();"
(dfBlur)="onBlur($event)"
(dfChange)="onChange($event)"
(dfFocus)="onFocus($event)">

View File

@@ -8,6 +8,7 @@ import {
DynamicFormGroupModel, DynamicFormLayout,
} from '@ng-dynamic-forms/core';
import { Store } from '@ngrx/store';
import { findIndex } from 'lodash';
import { AppState } from '../../app.reducer';
import {
@@ -37,6 +38,7 @@ import { isEmpty } from 'lodash';
})
export class FormComponent implements OnDestroy, OnInit {
private formErrors: FormError[] = [];
private formValid: boolean;
/**
@@ -44,6 +46,11 @@ export class FormComponent implements OnDestroy, OnInit {
*/
@Input() displaySubmit = true;
/**
* A boolean that indicate if to emit a form change event
*/
@Input() emitChange = true;
/**
* The form unique ID
*/
@@ -154,7 +161,9 @@ export class FormComponent implements OnDestroy, OnInit {
.subscribe((errors: FormError[]) => {
const {formGroup, formModel} = this;
errors.forEach((error: FormError) => {
errors
.filter((error: FormError) => findIndex(this.formErrors, {fieldId: error.fieldId}) === -1)
.forEach((error: FormError) => {
const {fieldId} = error;
let field: AbstractControl;
if (!!this.parentFormModel) {
@@ -166,9 +175,29 @@ export class FormComponent implements OnDestroy, OnInit {
if (field) {
const model: DynamicFormControlModel = this.formBuilderService.findById(fieldId, formModel);
this.formService.addErrorToField(field, model, error.message);
// this.formService.validateAllFormFields(formGroup);
this.changeDetectorRef.detectChanges();
}
});
this.formErrors
.filter((error: FormError) => findIndex(errors, {fieldId: error.fieldId}) === -1)
.forEach((error: FormError) => {
const {fieldId} = error;
let field: AbstractControl;
if (!!this.parentFormModel) {
field = this.formBuilderService.getFormControlById(fieldId, formGroup.parent as FormGroup, formModel);
} else {
field = this.formBuilderService.getFormControlById(fieldId, formGroup, formModel);
}
if (field) {
const model: DynamicFormControlModel = this.formBuilderService.findById(fieldId, formModel);
this.formService.removeErrorFromField(field, model, error.message);
}
});
this.formErrors = errors;
this.changeDetectorRef.detectChanges();
})
);
@@ -217,10 +246,11 @@ export class FormComponent implements OnDestroy, OnInit {
this.store.dispatch(action);
this.formGroup.markAsPristine();
this.change.emit(event);
const control: FormControl = event.control;
if (this.emitChange) {
this.change.emit(event);
}
// control.setErrors(null);
const control: FormControl = event.control;
if (control.valid) {
this.store.dispatch(new FormRemoveErrorAction(this.formId, event.model.id));
}

View File

@@ -7,9 +7,9 @@ import { AppState } from '../../app.reducer';
import { formObjectFromIdSelector } from './selectors';
import { FormBuilderService } from './builder/form-builder.service';
import { DynamicFormControlModel, DynamicFormGroupModel } from '@ng-dynamic-forms/core';
import { isNotEmpty, isNotUndefined } from '../empty.util';
import { isEmpty, isNotEmpty, isNotUndefined } from '../empty.util';
import { find, uniqueId } from 'lodash';
import { FormChangeAction } from './form.actions';
import { FormChangeAction, FormRemoveErrorAction } from './form.actions';
@Injectable()
export class FormService {
@@ -75,39 +75,46 @@ export class FormService {
}
public addErrorToField(field: AbstractControl, model: DynamicFormControlModel, message: string) {
const errorFound = !!(find(field.errors, (err) => err === message));
// search for the same error in the formControl.errors property
if (!errorFound) {
const errorKey = uniqueId('error-'); // create a single key for the error
const error = {}; // create the error object
const error = {}; // create the error object
error[errorKey] = message; // assign message
// if form control model has not errorMessages object, create it
if (!model.errorMessages) {
model.errorMessages = {};
}
// put the error in the form control model
model.errorMessages[errorKey] = message;
// Use correct error messages from the model
const lastArray = message.split('.');
if (lastArray && lastArray.length > 0) {
const last = lastArray[lastArray.length - 1];
const modelMsg = model.errorMessages[last];
if (modelMsg && modelMsg.length > 0) {
model.errorMessages[errorKey] = modelMsg;
}
}
// add the error in the form control
field.setErrors(error);
// formGroup.markAsDirty();
field.markAsTouched();
// if form control model has not errorMessages object, create it
if (!model.errorMessages) {
model.errorMessages = {};
}
// Use correct error messages from the model
const lastArray = message.split('.');
if (lastArray && lastArray.length > 0) {
// check if error code is already present in the set of model's validators
const last = lastArray[lastArray.length - 1];
const modelMsg = model.errorMessages[last];
if (isEmpty(modelMsg)) {
const errorKey = uniqueId('error-'); // create a single key for the error
error[errorKey] = true;
// put the error message in the form control model
model.errorMessages[errorKey] = message;
} else {
error[last] = modelMsg;
}
}
// add the error in the form control
field.setErrors(error);
field.markAsTouched();
}
public removeErrorFromField(field: AbstractControl, model: DynamicFormControlModel, message) {
const error = {};
// Use correct error messages from the model
const lastArray = message.split('.');
if (lastArray && lastArray.length > 0) {
const last = lastArray[lastArray.length - 1];
error[last] = null;
}
field.setErrors(error);
field.markAsUntouched();
}
public resetForm(formGroup: FormGroup, groupModel: DynamicFormControlModel[], formId: string) {