import { Injectable } from '@angular/core'; import { AbstractControl, FormGroup } from '@angular/forms'; import { DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX_GROUP, DYNAMIC_FORM_CONTROL_TYPE_GROUP, DYNAMIC_FORM_CONTROL_TYPE_RADIO_GROUP, DynamicFormArrayModel, DynamicFormControlModel, DynamicFormGroupModel, DynamicFormService, DynamicPathable, JSONUtils, } from '@ng-dynamic-forms/core'; 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, 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'; import { DynamicRowArrayModel } from './ds-dynamic-form-ui/models/ds-dynamic-row-array-model'; import { DsDynamicInputModel } from './ds-dynamic-form-ui/models/ds-dynamic-input.model'; import { FormFieldMetadataValueObject } from './models/form-field-metadata-value.model'; @Injectable() export class FormBuilderService extends DynamicFormService { findById(id: string, groupModel: DynamicFormControlModel[], arrayIndex = null): DynamicFormControlModel | null { let result = null; const findByIdFn = (findId: string, findGroupModel: DynamicFormControlModel[], findArrayIndex): void => { for (const controlModel of findGroupModel) { if (controlModel.id === findId) { if (this.isArrayGroup(controlModel) && isNotNull(findArrayIndex)) { result = (controlModel as DynamicFormArrayModel).get(findArrayIndex); } else { result = controlModel; } break; } if (this.isGroup(controlModel)) { findByIdFn(findId, (controlModel as DynamicFormGroupModel).group, findArrayIndex); } if (this.isArrayGroup(controlModel) && (isNull(findArrayIndex) || (controlModel as DynamicFormArrayModel).size > (findArrayIndex))) { const index = (isNull(findArrayIndex)) ? 0 : findArrayIndex; findByIdFn(findId, (controlModel as DynamicFormArrayModel).get(index).group, index); } } }; findByIdFn(id, groupModel, arrayIndex); return result; } clearAllModelsValue(groupModel: DynamicFormControlModel[]): void { const iterateControlModels = (findGroupModel: DynamicFormControlModel[]): void => { for (const controlModel of findGroupModel) { if (this.isGroup(controlModel)) { iterateControlModels((controlModel as DynamicFormGroupModel).group); continue; } if (this.isArrayGroup(controlModel)) { iterateControlModels((controlModel as DynamicFormArrayModel).groupFactory()); continue; } if (controlModel.hasOwnProperty('valueUpdates')) { (controlModel as any).valueUpdates.next(undefined); } } }; iterateControlModels(groupModel); } getValueFromModel(groupModel: DynamicFormControlModel[]): void { let result = Object.create({}); const customizer = (objValue, srcValue) => { if (Array.isArray(objValue)) { return objValue.concat(srcValue); } }; const normalizeValue = (controlModel, controlValue, controlModelIndex) => { const controlLanguage = (controlModel as DsDynamicInputModel).hasLanguages ? (controlModel as DsDynamicInputModel).language : null; if (isString(controlValue)) { return new FormFieldMetadataValueObject(controlValue, controlLanguage, null, null, controlModelIndex); } else if (isObject(controlValue)) { const authority = controlValue.authority || controlValue.id || null; const place = controlModelIndex || controlValue.place; return new FormFieldMetadataValueObject(controlValue.value, controlLanguage, authority, controlValue.display, place); } }; const iterateControlModels = (findGroupModel: DynamicFormControlModel[], controlModelIndex: number = 0): void => { let iterateResult = Object.create({}); // Iterate over all group's controls for (const controlModel of findGroupModel) { if (this.isRowGroup(controlModel) && !this.isCustomOrListGroup(controlModel)) { iterateResult = mergeWith(iterateResult, iterateControlModels((controlModel as DynamicFormGroupModel).group), customizer); continue; } if (this.isGroup(controlModel) && !this.isCustomOrListGroup(controlModel)) { iterateResult[controlModel.name] = iterateControlModels((controlModel as DynamicFormGroupModel).group); continue; } if (this.isRowArrayGroup(controlModel)) { for (const arrayItemModel of (controlModel as DynamicRowArrayModel).groups) { iterateResult = mergeWith(iterateResult, iterateControlModels(arrayItemModel.group, arrayItemModel.index), customizer); } continue; } if (this.isArrayGroup(controlModel)) { iterateResult[controlModel.name] = []; for (const arrayItemModel of (controlModel as DynamicFormArrayModel).groups) { iterateResult[controlModel.name].push(iterateControlModels(arrayItemModel.group, arrayItemModel.index)); } continue; } let controlId; // Get the field's name if (this.isQualdropGroup(controlModel)) { // If is instance of DynamicQualdropModel take the qualdrop id as field's name controlId = (controlModel as DynamicQualdropModel).qualdropId; } else { controlId = controlModel.name; } if (this.isRelationGroup(controlModel)) { const values = (controlModel as DynamicGroupModel).getGroupValue(); values.forEach((groupValue, groupIndex) => { const newGroupValue = Object.create({}); Object.keys(groupValue) .forEach((key) => { const normValue = normalizeValue(controlModel, groupValue[key], groupIndex); if (isNotEmpty(normValue) && normValue.hasValue()) { if (iterateResult.hasOwnProperty(key)) { iterateResult[key].push(normValue); } else { iterateResult[key] = [normValue]; } } }); }) } 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; }; result = iterateControlModels(groupModel); return result; } modelFromConfiguration(json: string | SubmissionFormsModel, scopeUUID: string, initFormValues: any = {}, submissionScope?: string, readOnly = false): DynamicFormControlModel[] | never { let rows: DynamicFormControlModel[] = []; const rawData = typeof json === 'string' ? JSON.parse(json, JSONUtils.parseReviver) : json; if (rawData.rows && !isEmpty(rawData.rows)) { rawData.rows.forEach((currentRow) => { const rowParsed = new RowParser(currentRow, scopeUUID, initFormValues, submissionScope, readOnly).parse(); if (isNotNull(rowParsed)) { if (Array.isArray(rowParsed)) { rows = rows.concat(rowParsed); } else { rows.push(rowParsed); } } }); } return rows; } isModelInCustomGroup(model: DynamicFormControlModel): boolean { return this.isCustomGroup((model as any).parent); } hasArrayGroupValue(model: DynamicFormControlModel): boolean { return model && (this.isListGroup(model) || model.type === DYNAMIC_FORM_CONTROL_TYPE_TAG); } hasMappedGroupValue(model: DynamicFormControlModel): boolean { return (this.isQualdropGroup((model as any).parent) || this.isRelationGroup((model as any).parent)); } isGroup(model: DynamicFormControlModel): boolean { return model && (model.type === DYNAMIC_FORM_CONTROL_TYPE_GROUP || model.type === DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX_GROUP); } isQualdropGroup(model: DynamicFormControlModel): boolean { return (model && model.type === DYNAMIC_FORM_CONTROL_TYPE_GROUP && hasValue((model as any).qualdropId)); } isCustomGroup(model: DynamicFormControlModel): boolean { return model && ((model as any).type === DYNAMIC_FORM_CONTROL_TYPE_GROUP && (model as any).isCustomGroup === true); } isRowGroup(model: DynamicFormControlModel): boolean { return model && ((model as any).type === DYNAMIC_FORM_CONTROL_TYPE_GROUP && (model as any).isRowGroup === true); } isCustomOrListGroup(model: DynamicFormControlModel): boolean { return model && (this.isCustomGroup(model) || this.isListGroup(model)); } isListGroup(model: DynamicFormControlModel): boolean { return model && ((model.type === DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX_GROUP && (model as any).isListGroup === true) || (model.type === DYNAMIC_FORM_CONTROL_TYPE_RADIO_GROUP && (model as any).isListGroup === true)); } isRelationGroup(model: DynamicFormControlModel): boolean { return model && model.type === DYNAMIC_FORM_CONTROL_TYPE_RELATION_GROUP; } isRowArrayGroup(model: DynamicFormControlModel): boolean { return model.type === DYNAMIC_FORM_CONTROL_TYPE_ARRAY && (model as any).isRowArray === true; } isArrayGroup(model: DynamicFormControlModel): boolean { return model.type === DYNAMIC_FORM_CONTROL_TYPE_ARRAY; } getFormControlById(id: string, formGroup: FormGroup, groupModel: DynamicFormControlModel[], index = 0): AbstractControl { const fieldModel = this.findById(id, groupModel, index); return isNotEmpty(fieldModel) ? formGroup.get(this.getPath(fieldModel)) : null; } getId(model: DynamicPathable): string { if (this.isArrayGroup(model as DynamicFormControlModel)) { return model.index.toString(); } else { return ((model as DynamicFormControlModel).id !== (model as DynamicFormControlModel).name) ? (model as DynamicFormControlModel).name : (model as DynamicFormControlModel).id; } } }