@ng-flexy/form
Version:
Flexy components and tools to build Angular 8+ applications
1 lines • 151 kB
Source Map (JSON)
{"version":3,"file":"ng-flexy-form.mjs","sources":["../../../projects/form/src/lib/components/attr.binder.utils.ts","../../../projects/form/src/lib/components/attributes.directive.ts","../../../projects/form/src/lib/components/container.directive.ts","../../../projects/form/src/lib/models/layout-json-schema.model.ts","../../../projects/form/src/lib/validators/validators.utils.ts","../../../projects/form/src/lib/services/json-mapper.utils.ts","../../../projects/form/src/lib/models/form.utils.ts","../../../projects/form/src/lib/models/form.model.ts","../../../projects/form/src/lib/form-options.token.ts","../../../projects/form/src/lib/services/json-mapper.service.ts","../../../projects/form/src/lib/components/if.directive.ts","../../../projects/form/src/lib/components/form-container.component.ts","../../../projects/form/src/lib/components/form.component.ts","../../../projects/form/src/lib/components/abstract-options.component.ts","../../../projects/form/src/lib/pipes/first-error.pipe.ts","../../../projects/form/src/lib/pipes/options-mapper.pipe.ts","../../../projects/form/src/lib/services/schema.service.ts","../../../projects/form/src/lib/services/schema.utils.ts","../../../projects/form/src/lib/services/form-control-options.service.ts","../../../projects/form/src/lib/services/form-control-raw-options.utils.ts","../../../projects/form/src/lib/ultils/utils.ts","../../../projects/form/src/lib/form.module.ts","../../../projects/form/src/public-api.ts","../../../projects/form/src/ng-flexy-form.ts"],"sourcesContent":["import { Renderer2 } from '@angular/core';\r\nimport { FlexyFormFieldLayoutSchema } from '../models/layout-schema.model';\r\nimport * as jsonata_ from 'jsonata';\r\nimport { FlexyFormData } from '../models/form.data';\r\nconst jsonata = jsonata_;\r\n\r\nexport function bindAttributes(schema: FlexyFormFieldLayoutSchema, nativeEl, renderer: Renderer2, data: FlexyFormData) {\r\n if (nativeEl && renderer && schema.attributes) {\r\n Object.keys(schema.attributes).forEach(attrKey => {\r\n if (typeof schema.attributes[attrKey] === 'object') {\r\n const attrValues: string[] = [];\r\n Object.keys(schema.attributes[attrKey]).forEach(oKey => {\r\n if (schema.attributes[attrKey][oKey]) {\r\n try {\r\n const is = jsonata(schema.attributes[attrKey][oKey]).evaluate(data);\r\n if (is) {\r\n attrValues.push(oKey);\r\n }\r\n } catch (e) {\r\n // do nothing\r\n }\r\n }\r\n });\r\n renderer.setAttribute(nativeEl, attrKey, attrValues.join(' '));\r\n } else if (typeof schema.attributes[attrKey] === 'string') {\r\n renderer.setAttribute(nativeEl, attrKey, schema.attributes[attrKey] as string);\r\n }\r\n });\r\n }\r\n}\r\n","import { Directive, ElementRef, Input, OnDestroy, OnInit, Renderer2 } from '@angular/core';\r\nimport { FlexyFormFieldLayoutSchema } from '../models/layout-schema.model';\r\nimport { FlexyForm } from '../models/form.model';\r\nimport { Subscription } from 'rxjs';\r\nimport { bindAttributes } from './attr.binder.utils';\r\n\r\n@Directive({\n selector: '[flexyFormAttributes]',\n standalone: false\n})\r\nexport class FlexyFormAttributesDirective implements OnInit, OnDestroy {\r\n @Input() flexyForm: FlexyForm;\r\n @Input() componentSchema: FlexyFormFieldLayoutSchema;\r\n\r\n private _changesSubscription: Subscription;\r\n\r\n constructor(private renderer: Renderer2, private el: ElementRef) {}\r\n\r\n ngOnInit() {\r\n if (this.componentSchema && this.componentSchema.attributes) {\r\n bindAttributes(this.componentSchema, this.el.nativeElement, this.renderer, this.flexyForm.currentData);\r\n this._changesSubscription = this.flexyForm.currentData$.subscribe(data => {\r\n bindAttributes(this.componentSchema, this.el.nativeElement, this.renderer, data);\r\n });\r\n }\r\n }\r\n\r\n ngOnDestroy(): void {\r\n if (this._changesSubscription) {\r\n this._changesSubscription.unsubscribe();\r\n }\r\n }\r\n}\r\n","import { ComponentFactoryResolver, Directive, Input, OnDestroy, OnInit, Renderer2, ViewContainerRef } from '@angular/core';\r\nimport { FlexyFormFieldLayoutSchema } from '../models/layout-schema.model';\r\nimport { FlexyForm } from '../models/form.model';\r\nimport { Subscription } from 'rxjs';\r\nimport { bindAttributes } from './attr.binder.utils';\r\n\r\nconst LAYOUT_SCHEMA_KEY = 'layoutSchema';\r\nconst LAYOUT_FORM_KEY = 'form';\r\n\r\n@Directive({\n selector: '[flexyFormContainer]',\n standalone: false\n})\r\nexport class FlexyFormContainerDirective implements OnInit, OnDestroy {\r\n @Input() flexyForm: FlexyForm;\r\n\r\n @Input() set componentSchema(schema: FlexyFormFieldLayoutSchema) {\r\n this._schema = schema;\r\n }\r\n\r\n get componentSchema(): FlexyFormFieldLayoutSchema {\r\n return this._schema;\r\n }\r\n\r\n private _schema: FlexyFormFieldLayoutSchema;\r\n private _changesSubscription: Subscription;\r\n private _componentRef;\r\n\r\n constructor(private vc: ViewContainerRef, private resolver: ComponentFactoryResolver, private renderer: Renderer2) {}\r\n\r\n ngOnInit() {\r\n if (!this._schema) {\r\n return;\r\n }\r\n if (!this._schema.componentType) {\r\n return;\r\n }\r\n\r\n const componentFactory = this.resolver.resolveComponentFactory(this._schema.componentType);\r\n\r\n const viewContainerRef = this.vc;\r\n viewContainerRef.clear();\r\n\r\n const componentRef = viewContainerRef.createComponent(componentFactory);\r\n\r\n componentRef.instance[LAYOUT_SCHEMA_KEY] = this._schema;\r\n componentRef.instance[LAYOUT_FORM_KEY] = this.flexyForm;\r\n this._schema.componentRef = componentRef;\r\n\r\n if (this._schema.componentInputs) {\r\n Object.keys(this._schema.componentInputs).forEach(key => {\r\n componentRef.instance[key] = this._schema.componentInputs[key];\r\n });\r\n }\r\n\r\n this._componentRef = componentRef;\r\n if (this._schema.attributes) {\r\n bindAttributes(this._schema, this._componentRef.location.nativeElement, this.renderer, this.flexyForm.currentData);\r\n }\r\n\r\n this._changesSubscription = this.flexyForm.currentData$.subscribe(data => {\r\n if (this._componentRef) {\r\n bindAttributes(this.componentSchema, this._componentRef.location.nativeElement, this.renderer, data);\r\n }\r\n });\r\n }\r\n\r\n ngOnDestroy(): void {\r\n if (this._changesSubscription) {\r\n this._changesSubscription.unsubscribe();\r\n }\r\n }\r\n}\r\n","import { FlexyLayoutComponentJsonSchema, FlexyLayoutJson, FlexyLayoutGridJsonSchema } from '@ng-flexy/layout';\r\n\r\nexport const COMPLEX_TYPE_INDEX_MARKER = '{%}';\r\n\r\nexport enum FlexyFormFieldType {\r\n String = 'string',\r\n Number = 'number',\r\n Boolean = 'boolean',\r\n Array = 'array',\r\n Group = 'group'\r\n}\r\n\r\nexport interface FlexyFormLayoutJson extends FlexyLayoutJson {\r\n schema: FlexyFormLayoutJsonSchema[];\r\n}\r\n\r\nexport type FlexyFormLayoutJsonSchema =\r\n | FlexyFormFieldLayoutJsonSchema\r\n | FlexyFormComplexFieldLayoutJsonSchema\r\n | FlexyFormIfJsonSchema\r\n | FlexyFormCalcJsonSchema\r\n | FlexyFormGridJsonSchema\r\n | FlexyFormComponentJsonSchema;\r\n\r\nexport interface FlexyFormGridJsonSchema extends FlexyLayoutGridJsonSchema {\r\n children?: FlexyFormLayoutJsonSchema[];\r\n}\r\n\r\nexport interface FlexyFormComponentJsonSchema extends FlexyLayoutComponentJsonSchema {\r\n children?: FlexyFormLayoutJsonSchema[];\r\n}\r\n\r\nexport interface FlexyFormIfJsonSchema extends FlexyFormGridJsonSchema {\r\n if: string;\r\n}\r\n\r\nexport interface FlexyFormCalcJsonSchema extends FlexyFormComponentJsonSchema {\r\n calc: string;\r\n name?: string;\r\n}\r\n\r\nexport interface FlexyFormFieldLayoutJsonSchema extends FlexyFormComponentJsonSchema {\r\n name: string;\r\n type?: FlexyFormFieldType;\r\n validators?: FlexyFormFieldLayoutValidators;\r\n}\r\n\r\nexport interface FlexyFormComplexFieldLayoutJsonSchema extends FlexyFormFieldLayoutJsonSchema {\r\n items: FlexyFormLayoutJsonSchema;\r\n indexDef?: string;\r\n indexPattern?: string;\r\n indexGenPattern?: string;\r\n\r\n // for dynamic groups\r\n groupKey?: string; // ???\r\n}\r\n\r\nexport interface FlexyFormFieldLayoutValidators {\r\n [validatorName: string]: any;\r\n}\r\n","import { FormControl, ValidatorFn, FormArray } from '@angular/forms';\r\nimport { cloneDeep, uniq } from 'lodash';\r\n\r\ntype ControlPath = (string | number)[] | string;\r\n\r\nexport interface CrossFieldsOptions {\r\n lower: {\r\n name: string;\r\n path: ControlPath;\r\n };\r\n greater: {\r\n name: string;\r\n path: ControlPath;\r\n };\r\n}\r\n\r\nexport namespace FlexyFormsValidators {\r\n export function notEmptyValidator(control: FormControl) {\r\n if (!control) {\r\n return null;\r\n }\r\n if (FlexyFormsValidators.isEmpty(control)) {\r\n return {\r\n 'not-empty': true\r\n };\r\n }\r\n return null;\r\n }\r\n\r\n export function noWhitespaceValidator(control: FormControl) {\r\n if (!control) {\r\n return null;\r\n }\r\n if ((control.value || '').trim().length === 0) {\r\n return { whitespace: true };\r\n }\r\n return null;\r\n }\r\n\r\n export function emailValidator(control: FormControl) {\r\n if (!control) {\r\n return null;\r\n }\r\n const re = new RegExp(\r\n [\r\n '^(([^<>()\\\\[\\\\]\\\\\\\\.,;:!#\\\\s@\"]+(\\\\.[^<>()\\\\[\\\\]\\\\\\\\.,;:!#\\\\s@\"]+)*)|(\".+\"))@',\r\n '((\\\\[[0-9]{1,3}\\\\.[0-9]{1,3}\\\\.[0-9]{1,3}\\\\.[0-9]{1,3}])|(([a-zA-Z\\\\-0-9]+\\\\.)',\r\n '+[a-zA-Z]{2,})|([a-zA-Z\\\\-0-9]+))$'\r\n ].join('')\r\n );\r\n if (!FlexyFormsValidators.isEmpty(control) && !re.test(control.value)) {\r\n return {\r\n 'invalid-email': {\r\n currentValue: control.value\r\n }\r\n };\r\n }\r\n return null;\r\n }\r\n\r\n export function booleanValidator(control: FormControl) {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!FlexyFormsValidators.isEmpty(control) && typeof control.value !== 'boolean') {\r\n return {\r\n 'invalid-boolean': {\r\n currentValue: control.value\r\n }\r\n };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n export function integerValidator(control: FormControl) {\r\n if (!control) {\r\n return null;\r\n }\r\n const re = /^-?\\d+$/;\r\n if (!FlexyFormsValidators.isEmpty(control) && !re.test(control.value)) {\r\n return {\r\n 'invalid-integer': {\r\n currentValue: control.value\r\n }\r\n };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n export function minValidator(min: number): ValidatorFn {\r\n return (control: FormControl) => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!(min || min === 0)) {\r\n return {\r\n 'invalid-min': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n const notNumber = FlexyFormsValidators.numberValidator(control);\r\n if (notNumber) {\r\n return notNumber;\r\n }\r\n if ((!FlexyFormsValidators.isEmpty(control) || control.value === 0) && control.value < min) {\r\n return {\r\n 'invalid-min': {\r\n minimumValue: min,\r\n currentValue: control.value\r\n }\r\n };\r\n }\r\n return null;\r\n };\r\n }\r\n\r\n export function maxValidator(max: number): ValidatorFn {\r\n return (control: FormControl) => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!(max || max === 0)) {\r\n return {\r\n 'invalid-max': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n const notNumber = FlexyFormsValidators.numberValidator(control);\r\n if (notNumber) {\r\n return notNumber;\r\n }\r\n if ((!FlexyFormsValidators.isEmpty(control) || control.value === 0) && control.value > max) {\r\n return {\r\n 'invalid-max': {\r\n maximumValue: max,\r\n currentValue: control.value\r\n }\r\n };\r\n }\r\n return null;\r\n };\r\n }\r\n\r\n export function numberValidator(control: FormControl) {\r\n if (!control) {\r\n return null;\r\n }\r\n const re = /^-?(\\d+\\.?\\d*)$|^(\\d*\\.?\\d+)$/;\r\n if (!FlexyFormsValidators.isEmpty(control) && !re.test(control.value)) {\r\n return {\r\n 'invalid-number': {\r\n currentValue: control.value\r\n }\r\n };\r\n }\r\n\r\n return null;\r\n }\r\n\r\n export function minLengthArray(min: number) {\r\n return (control: FormControl): { [key: string]: any } => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!(min || min === 0)) {\r\n return {\r\n 'min-length-array': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n if (control.value && Array.isArray(control.value) && control.value.length >= min) {\r\n return null;\r\n }\r\n return {\r\n 'min-length-array': {\r\n minimumLength: min,\r\n currentLength: control.value\r\n }\r\n };\r\n };\r\n }\r\n\r\n export function maxLengthArray(max: number) {\r\n return (control: FormControl): { [key: string]: any } => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!(max || max === 0)) {\r\n return {\r\n 'max-length-array': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n if (control.value && control.value.length <= max) {\r\n return null;\r\n }\r\n return {\r\n 'max-length-array': {\r\n maximumLength: max,\r\n currentLength: control.value\r\n }\r\n };\r\n };\r\n }\r\n\r\n export function isEmpty(control: FormControl) {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!control.value || (Array.isArray(control.value) && control.value.length === 0)) {\r\n return true;\r\n } else {\r\n return false;\r\n }\r\n }\r\n\r\n export function urlValidator(control: FormControl) {\r\n if (!control) {\r\n return null;\r\n }\r\n const re = new RegExp(\r\n [\r\n '((([A-Za-z]{3,9}:(?:\\\\/\\\\/)?)(?:[\\\\-;:&=\\\\+\\\\$,\\\\w]+@)?[A-Za-z0-9\\\\.\\\\-]',\r\n '+|(?:www\\\\.|[\\\\-;:&=\\\\+\\\\$,\\\\w]+@)[A-Za-z0-9\\\\.\\\\-]+)((?:\\\\/[\\\\+~%\\\\/\\\\.\\\\w\\\\-_]*)?\\\\??',\r\n '(?:[\\\\-\\\\+=&;%@\\\\.\\\\w_]*)#?(?:[\\\\.\\\\!\\\\/\\\\\\\\\\\\w]*))?)'\r\n ].join('')\r\n );\r\n if (!FlexyFormsValidators.isEmpty(control) && !re.test(control.value)) {\r\n return {\r\n 'invalid-url': {\r\n currentValue: control.value\r\n }\r\n };\r\n }\r\n return null;\r\n }\r\n\r\n export function crossFieldValidator(fields: CrossFieldsOptions) {\r\n return (control: FormControl): { [key: string]: any } => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!(fields && fields.lower && fields.greater)) {\r\n return {\r\n 'cross-field-invalid': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n const lower: FormControl = getControl(fields.lower.path, control);\r\n const greater: FormControl = getControl(fields.greater.path, control);\r\n\r\n if (!(greater && greater.valid && lower && lower.valid && greater.value < lower.value)) {\r\n return null;\r\n }\r\n return {\r\n 'cross-field-invalid': {\r\n greater: fields.greater.name,\r\n greaterPath: fields.greater.path,\r\n greaterValue: greater && greater.value,\r\n lower: fields.lower.name,\r\n lowerPath: fields.lower.path,\r\n lowerValue: lower && lower.value\r\n }\r\n };\r\n };\r\n }\r\n\r\n export function crossFieldMinValidator(minPath: ControlPath) {\r\n return (control: FormControl): { [key: string]: any } => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!minPath) {\r\n return {\r\n 'invalid-min': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n const min: FormControl = getControl(minPath, control);\r\n if (!(min && control.valid && control.value < min.value)) {\r\n return null;\r\n }\r\n return {\r\n 'invalid-min': {\r\n minimumValue: min.value,\r\n currentValue: control.value\r\n }\r\n };\r\n };\r\n }\r\n\r\n export function crossFieldMaxValidator(maxPath: ControlPath) {\r\n return (control: FormControl): { [key: string]: any } => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!maxPath) {\r\n return {\r\n 'invalid-max': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n const max: FormControl = getControl(maxPath, control);\r\n if (!(max && control.valid && control.value > max.value)) {\r\n return null;\r\n }\r\n return {\r\n 'invalid-max': {\r\n maximumValue: max.value,\r\n currentValue: control.value\r\n }\r\n };\r\n };\r\n }\r\n\r\n export function crossFieldAbsoluteMinValidator(minPath: ControlPath) {\r\n return (control: FormControl): { [key: string]: any } => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!minPath) {\r\n return {\r\n 'absolute-min-invalid': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n const min: FormControl = getControl(minPath, control);\r\n if (min && control.valid && min.valid && Math.abs(control.value) >= min.value) {\r\n return null;\r\n }\r\n return {\r\n 'absolute-min-invalid': {\r\n min: min.value,\r\n currentValue: control.value\r\n }\r\n };\r\n };\r\n }\r\n\r\n export function forbiddenValuesValidator(forbiddenValues: (string | number)[]) {\r\n return (control: FormControl): { [key: string]: any } => {\r\n if (!control) {\r\n return null;\r\n }\r\n if (!forbiddenValues) {\r\n return {\r\n 'forbidden-value': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n if (!forbiddenValues.includes(control.value)) {\r\n return null;\r\n }\r\n return {\r\n 'forbidden-value': {\r\n value: control.value\r\n }\r\n };\r\n };\r\n }\r\n\r\n export function arrayUniqueFieldsValidator(data: { path: ControlPath; fieldName: string }) {\r\n return (control: FormArray): { [key: string]: any } => {\r\n if (!control || !control.controls) {\r\n return null;\r\n }\r\n if (!(data && data.path)) {\r\n return {\r\n 'value-duplicate': {\r\n wrongConfiguration: true\r\n }\r\n };\r\n }\r\n const comparedValues = [];\r\n control.controls.forEach(item => {\r\n const compared = getControl(data.path, item);\r\n if (compared) {\r\n comparedValues.push(compared.value);\r\n }\r\n });\r\n if (uniq(comparedValues).length === comparedValues.length) {\r\n return null;\r\n }\r\n return {\r\n 'value-duplicate': {\r\n field: data.fieldName\r\n }\r\n };\r\n };\r\n }\r\n\r\n function getControl(path: ControlPath, control): FormControl {\r\n let arrayPath: (string | number)[] = [];\r\n if (Array.isArray(path)) {\r\n arrayPath = path;\r\n } else if (path) {\r\n const parents: (string | number)[] = ('' + path).indexOf('../') !== -1 ? path.split('../') : [path];\r\n const sPath = '' + parents.pop();\r\n const stringPath = sPath.split('.').map(i => {\r\n if (i.match(/^[0-9]+$/)) {\r\n return parseInt(i, 10);\r\n } else {\r\n return i;\r\n }\r\n });\r\n parents.fill('../');\r\n parents.push(...stringPath);\r\n arrayPath = parents;\r\n }\r\n arrayPath.forEach(i => {\r\n if (control && control.parent && i === '../') {\r\n control = control.parent;\r\n } else if (control && control.controls) {\r\n control = Number.isInteger(i) ? control.get(Object.keys(control.controls)[i]) : control.controls[i];\r\n }\r\n });\r\n return control;\r\n }\r\n}\r\n","import {\r\n FlexyFormCalcJsonSchema,\r\n FlexyFormFieldLayoutJsonSchema,\r\n FlexyFormFieldType,\r\n FlexyFormIfJsonSchema,\r\n FlexyFormLayoutJson,\r\n FlexyFormLayoutJsonSchema\r\n} from '../models/layout-json-schema.model';\r\n\r\nexport const HIDDEN_IF_GROUP_NAME = '__if__';\r\nexport const HIDDEN_CALC_GROUP_NAME = '__calc__';\r\n\r\nexport function parseFormJson(json: FlexyFormLayoutJson): FlexyFormLayoutJsonSchema[] {\r\n if (Array.isArray(json)) {\r\n return parseFormVersion1(json);\r\n } else if (json.schemaVersion === 1) {\r\n return parseFormVersion1(json.schema);\r\n } else {\r\n const schema = json.schema;\r\n assignHiddenNames(schema);\r\n checkSchema(schema);\r\n return json.schema;\r\n }\r\n}\r\n\r\nexport function checkSchema(schema: FlexyFormLayoutJsonSchema[]) {\r\n if (schema && Array.isArray(schema)) {\r\n schema.forEach((jsonItem, index) => {\r\n if (\r\n (jsonItem as FlexyFormIfJsonSchema).if &&\r\n ((jsonItem as FlexyFormFieldLayoutJsonSchema).name || (jsonItem as FlexyFormFieldLayoutJsonSchema).type)\r\n ) {\r\n console.warn('Wrong if schema', jsonItem);\r\n }\r\n if (jsonItem.children) {\r\n checkSchema(jsonItem.children);\r\n }\r\n });\r\n }\r\n}\r\n\r\nexport function assignHiddenNames(schema: FlexyFormLayoutJsonSchema[]) {\r\n if (schema && Array.isArray(schema)) {\r\n schema.forEach((jsonItem, index) => {\r\n // if ((jsonItem as FlexyFormIfJsonSchema).if && !(jsonItem as FlexyFormFieldLayoutJsonSchema).type) {\r\n // (jsonItem as FlexyFormFieldLayoutJsonSchema).type = FlexyFormFieldType.Group;\r\n // }\r\n if ((jsonItem as FlexyFormCalcJsonSchema).calc && !(jsonItem as FlexyFormFieldLayoutJsonSchema).name) {\r\n (jsonItem as FlexyFormFieldLayoutJsonSchema).name =\r\n HIDDEN_CALC_GROUP_NAME +\r\n '.' +\r\n (jsonItem.id\r\n ? jsonItem.id\r\n : 'ui-' +\r\n Math.random()\r\n .toString(36)\r\n .substr(2, 9));\r\n }\r\n if (jsonItem.children) {\r\n assignHiddenNames(jsonItem.children);\r\n }\r\n });\r\n }\r\n}\r\n\r\nexport function parseFormVersion1(json: any[]): FlexyFormLayoutJsonSchema[] {\r\n const parsed: FlexyFormLayoutJsonSchema[] = [];\r\n json.forEach(item => {\r\n parsed.push(parseFormVersion1Item(item));\r\n });\r\n return parsed as FlexyFormLayoutJsonSchema[];\r\n}\r\n\r\nexport function parseFormVersion1Item(item: any): FlexyFormLayoutJsonSchema {\r\n const schema = {} as FlexyFormLayoutJsonSchema;\r\n if (item.properties && item.properties.class) {\r\n if (!schema.attributes) {\r\n schema.attributes = {};\r\n }\r\n schema.attributes.class = item.properties.class;\r\n }\r\n if (item.component) {\r\n Object.assign(schema, {\r\n component: item.component,\r\n properties: item.componentInputs ? item.componentInputs : {}\r\n });\r\n }\r\n\r\n if (item.controlGroupName) {\r\n Object.assign(schema, {\r\n name: item.controlGroupName,\r\n type: FlexyFormFieldType.Group,\r\n validators: item.validators,\r\n groupKey: item.groupKey,\r\n items: item.items ? parseFormVersion1Item(item.items) : void 0,\r\n indexDef: item.itemKeyDef,\r\n indexPattern: item.itemKeyPattern,\r\n indexGenPattern: item.itemKeyGen\r\n });\r\n } else if (item.controlArrayName) {\r\n Object.assign(schema, {\r\n name: item.controlArrayName,\r\n type: FlexyFormFieldType.Array,\r\n validators: item.validators,\r\n items: item.items ? parseFormVersion1Item(item.items) : void 0,\r\n indexDef: item.itemIndexDef\r\n });\r\n } else if (item.controlName) {\r\n Object.assign(schema, {\r\n name: item.controlName,\r\n validators: item.validators\r\n });\r\n }\r\n\r\n if (item.children) {\r\n schema.children = parseFormVersion1(item.children);\r\n }\r\n\r\n return schema;\r\n}\r\n\r\nexport function replaceMarker(s: string, marker: string, key: string | number) {\r\n return s.split(marker).join('' + key);\r\n}\r\n","import { FlexyFormFieldLayoutSchema, FlexyFormLayoutSchema } from './layout-schema.model';\r\nimport { FlexyFormData } from './form.data';\r\nimport { AbstractControl, FormArray, FormControl } from '@angular/forms';\r\nimport { get, has, merge, set } from 'lodash';\r\nimport * as jsonata_ from 'jsonata';\r\n\r\nconst jsonata = jsonata_;\r\n\r\nconst ifExpressionsCache = {};\r\nconst calculatedExpresionCache = {};\r\n\r\nexport enum FlexyFormDataMode {\r\n All = 'all',\r\n Dirty = 'dirty',\r\n Touched = 'toched'\r\n}\r\n\r\nexport function findErrors(schema: FlexyFormLayoutSchema[], currentData: FlexyFormData): { [key: string]: any } {\r\n const errors = {};\r\n for (const item of schema) {\r\n if (checkIf(item as FlexyFormFieldLayoutSchema, currentData) && (item as FlexyFormFieldLayoutSchema).items) {\r\n (item as FlexyFormFieldLayoutSchema).items.forEach((aItem, index) => {\r\n const arrItemError = findErrors([aItem], currentData);\r\n if (arrItemError && Object.values(arrItemError).length) {\r\n errors[(item as FlexyFormFieldLayoutSchema).formName + '.' + index] = arrItemError;\r\n }\r\n });\r\n } else if (\r\n checkIf(item as FlexyFormFieldLayoutSchema, currentData) &&\r\n (item as FlexyFormFieldLayoutSchema).formName &&\r\n (item as FlexyFormFieldLayoutSchema).formControl &&\r\n (item as FlexyFormFieldLayoutSchema).formControl.invalid\r\n ) {\r\n errors[(item as FlexyFormFieldLayoutSchema).formName] = (item as FlexyFormFieldLayoutSchema).formControl.errors;\r\n }\r\n if (checkIf(item as FlexyFormFieldLayoutSchema, currentData) && item.children) {\r\n Object.assign(errors, findErrors(item.children, currentData));\r\n }\r\n }\r\n return errors;\r\n}\r\n\r\nexport function findSchema(fieldName: string, schema: FlexyFormLayoutSchema[]): FlexyFormFieldLayoutSchema {\r\n for (const item of schema) {\r\n if ((item as FlexyFormFieldLayoutSchema).formName && (item as FlexyFormFieldLayoutSchema).formName === fieldName) {\r\n return item as FlexyFormFieldLayoutSchema;\r\n } else if (item.children) {\r\n const childSchema = findSchema(fieldName, item.children);\r\n if (childSchema) {\r\n return childSchema;\r\n }\r\n }\r\n }\r\n return null;\r\n}\r\n\r\nexport function calculate(calcExp: string, data: any) {\r\n let value;\r\n try {\r\n if (!calculatedExpresionCache[calcExp]) {\r\n calculatedExpresionCache[calcExp] = jsonata(calcExp);\r\n }\r\n value = calculatedExpresionCache[calcExp].evaluate(data);\r\n } catch (e) {\r\n // console.error(e);\r\n value = null;\r\n }\r\n return value;\r\n}\r\n\r\nexport function getSchemaData(schemas: FlexyFormLayoutSchema[], currentData: FlexyFormData, mode = FlexyFormDataMode.All): FlexyFormData {\r\n let data: FlexyFormData = {};\r\n if (schemas) {\r\n schemas.forEach(schema => {\r\n const fieldSchema: FlexyFormFieldLayoutSchema = schema as FlexyFormFieldLayoutSchema;\r\n if (checkIf(fieldSchema, currentData)) {\r\n const isFormControl = fieldSchema.formControl && fieldSchema.formName;\r\n if (isFormControl && fieldSchema.formControl instanceof FormControl) {\r\n if (checkSchemaData(fieldSchema.formControl, mode)) {\r\n set(data, fieldSchema.formName, fieldSchema.formControl.value);\r\n }\r\n } else if (isFormControl && fieldSchema.formControl instanceof FormArray) {\r\n const arrayData = getArrayData(fieldSchema, currentData, mode, data);\r\n\r\n if (mode === FlexyFormDataMode.All) {\r\n set(data, fieldSchema.formName, Object.values(arrayData));\r\n } else if (!isInputEmpty(arrayData)) {\r\n set(data, fieldSchema.formName, arrayData);\r\n }\r\n }\r\n\r\n if (checkIf(fieldSchema, currentData)) {\r\n data = merge(data, getSchemaData(fieldSchema.children, currentData, mode));\r\n }\r\n }\r\n });\r\n }\r\n return data;\r\n}\r\n\r\nexport function findRemoved(allData, originalData) {\r\n const removed = {};\r\n if (originalData) {\r\n Object.keys(originalData).forEach(key => {\r\n const path = key;\r\n if (!isInputEmpty(originalData[key]) && isInputEmpty(allData[key])) {\r\n set(removed, path, null);\r\n } else if (originalData[key] && Array.isArray(originalData[key])) {\r\n originalData[key].forEach((item, index) => {\r\n if (!isInputEmpty(item) && isInputEmpty(allData[key][index])) {\r\n if (!has(removed, path)) {\r\n set(removed, path, {});\r\n }\r\n const v = get(removed, path);\r\n v['' + index] = null;\r\n } else if (item && isObject(item)) {\r\n const founded = findRemoved(allData[key][index], item);\r\n if (founded && !isInputEmpty(founded)) {\r\n if (!has(removed, path)) {\r\n set(removed, path, {});\r\n }\r\n const v = get(removed, path);\r\n v['' + index] = founded;\r\n }\r\n }\r\n });\r\n } else if (originalData[key] && isObject(originalData[key])) {\r\n const founded = findRemoved(allData[key], originalData[key]);\r\n if (founded && !isInputEmpty(founded)) {\r\n set(removed, path, founded);\r\n }\r\n }\r\n });\r\n }\r\n return removed;\r\n}\r\n\r\nexport function clearEmptyArrayAndObjects(data: { [key: string]: any }) {\r\n if (data) {\r\n if (isObject(data)) {\r\n Object.keys(data).forEach(key => {\r\n if (isEmptyStructure(data[key])) {\r\n delete data[key];\r\n } else if (isObject(data[key])) {\r\n clearEmptyArrayAndObjects(data[key]);\r\n }\r\n });\r\n }\r\n }\r\n}\r\n\r\nfunction isObject(a) {\r\n return !!a && a.constructor === Object;\r\n}\r\n\r\nfunction checkIf(fieldSchema: FlexyFormFieldLayoutSchema, currentData: FlexyFormData): boolean {\r\n if (!fieldSchema.if) {\r\n return true;\r\n }\r\n const ifName = 'IF_' + fieldSchema.if;\r\n let ret;\r\n try {\r\n if (!ifExpressionsCache[ifName]) {\r\n ifExpressionsCache[ifName] = jsonata(fieldSchema.if);\r\n }\r\n ret = ifExpressionsCache[ifName].evaluate(currentData ? currentData : {});\r\n } catch (e) {\r\n // console.error(e);\r\n ret = null;\r\n }\r\n return !!ret;\r\n}\r\n\r\nfunction getArrayData(\r\n fieldSchema: FlexyFormFieldLayoutSchema,\r\n currentData: FlexyFormData,\r\n mode: FlexyFormDataMode,\r\n data: {[name: string]: any}\r\n) {\r\n const arrayData = {};\r\n fieldSchema.items.forEach((item: FlexyFormLayoutSchema, index) => {\r\n const itemFormControl = (item as FlexyFormFieldLayoutSchema).formControl;\r\n if (!itemFormControl || checkSchemaData(itemFormControl, mode)) {\r\n if (item.children) {\r\n const itemData = getSchemaData(item.children, currentData, mode);\r\n if (!isInputEmpty(itemData)) {\r\n arrayData['' + index] = itemData;\r\n }\r\n } else {\r\n arrayData['' + index] = (item as FlexyFormFieldLayoutSchema).formControl.value;\r\n }\r\n }\r\n });\r\n\r\n return arrayData;\r\n}\r\n\r\nfunction checkSchemaData(control: AbstractControl, mode: FlexyFormDataMode) {\r\n return (\r\n control &&\r\n (mode === FlexyFormDataMode.All ||\r\n (mode === FlexyFormDataMode.Dirty && control.dirty) ||\r\n (mode === FlexyFormDataMode.Touched && control.touched))\r\n );\r\n}\r\n\r\nfunction isInputEmpty(v) {\r\n return v === void 0 || v === '';\r\n}\r\n\r\nfunction isEmptyStructure(data: any) {\r\n let ret = true;\r\n if (Array.isArray(data)) {\r\n if (data.length > 0) {\r\n data.forEach(item => {\r\n ret = ret && isEmptyStructure(item);\r\n });\r\n }\r\n } else if (isObject(data)) {\r\n if (Object.keys(data).length > 0) {\r\n Object.keys(data).forEach(key => {\r\n ret = ret && isEmptyStructure(data[key]);\r\n });\r\n }\r\n } else {\r\n return isInputEmpty(data);\r\n }\r\n return ret;\r\n}\r\n","import { FormControl, FormGroup } from '@angular/forms';\r\nimport { FlexyLayout } from '@ng-flexy/layout';\r\nimport { FlexyFormFieldLayoutSchema, FlexyFormLayoutSchema } from './layout-schema.model';\r\nimport { FlexyFormData } from './form.data';\r\nimport { cloneDeep, merge } from 'lodash';\r\nimport { BehaviorSubject, Observable, Subscription } from 'rxjs';\r\nimport { HIDDEN_CALC_GROUP_NAME } from '../services/json-mapper.utils';\r\nimport { calculate, clearEmptyArrayAndObjects, findErrors, findRemoved, findSchema, FlexyFormDataMode, getSchemaData } from './form.utils';\r\n\r\ninterface CalcRefs {\r\n [name: string]: {\r\n calc: string;\r\n control: FormControl;\r\n ifControl?: FormGroup;\r\n };\r\n}\r\n\r\ninterface IfRefs {\r\n if: string;\r\n state: boolean;\r\n ifControl?: FormGroup;\r\n}\r\n\r\nexport class FlexyForm extends FlexyLayout {\r\n currentData: FlexyFormData;\r\n currentDataHash: string;\r\n\r\n readonly currentData$: Observable<FlexyFormData>;\r\n\r\n get valid() {\r\n return !this.getAllErrors();\r\n }\r\n\r\n isStarted = false;\r\n\r\n // TODO to think change to private\r\n declare readonly schema: FlexyFormLayoutSchema[];\r\n readonly formGroup: FormGroup;\r\n\r\n private readonly _originalData: FlexyFormData;\r\n private readonly _currentDataSubject: BehaviorSubject<FlexyFormData>;\r\n\r\n _calculatedRefs: CalcRefs = {};\r\n\r\n _lastErrors: { [key: string]: any };\r\n\r\n private _changesSubscription: Subscription;\r\n\r\n constructor(formGroup: FormGroup, schema: FlexyFormLayoutSchema[], data: FlexyFormData) {\r\n super(schema);\r\n\r\n this._currentDataSubject = new BehaviorSubject(data);\r\n this.currentData$ = this._currentDataSubject.asObservable();\r\n\r\n this.formGroup = formGroup;\r\n this.schema = schema;\r\n\r\n this._initCalculatedRefs(schema);\r\n this._originalData = cloneDeep(data);\r\n this._setCurrentData();\r\n // refresh attributes\r\n this._setCurrentData();\r\n\r\n // jump to next tick\r\n // setTimeout(() => {\r\n this._subscribeChangesAndCalculate();\r\n // });\r\n }\r\n\r\n getAllData(): FlexyFormData {\r\n const data = cloneDeep(getSchemaData(this.schema, this.currentData));\r\n this._clearHiddenData(data);\r\n return data;\r\n }\r\n\r\n // @deprecated\r\n getDirtyData(): FlexyFormData {\r\n const data = cloneDeep(getSchemaData(this.schema, this.currentData, FlexyFormDataMode.Dirty));\r\n this._clearHiddenData(data);\r\n clearEmptyArrayAndObjects(data);\r\n const allData = this.getAllData();\r\n const removed = findRemoved(allData, this._originalData);\r\n clearEmptyArrayAndObjects(removed);\r\n return merge(data, removed);\r\n }\r\n\r\n getAllErrors(): { [key: string]: any } {\r\n return this._lastErrors;\r\n }\r\n\r\n containsFieldSchema(fieldName: string): boolean {\r\n return !!findSchema(fieldName, this.schema);\r\n }\r\n getFieldSchema(fieldName: string): FlexyFormFieldLayoutSchema {\r\n return findSchema(fieldName, this.schema);\r\n }\r\n getFieldInstance<T>(fieldName: string): T {\r\n const schema: FlexyFormFieldLayoutSchema = findSchema(fieldName, this.schema);\r\n if (schema && schema.componentRef) {\r\n return schema.componentRef.instance;\r\n }\r\n return null;\r\n }\r\n\r\n private _subscribeChangesAndCalculate() {\r\n this._setCurrentData();\r\n this.isStarted = true;\r\n // this._setCurrentData();\r\n this._changesSubscription = this.formGroup.valueChanges.subscribe(data => {\r\n const hash = this.currentDataHash;\r\n this._setCurrentData();\r\n if (hash !== this.currentDataHash) {\r\n this._currentDataSubject.next(this.currentData);\r\n }\r\n });\r\n this._currentDataSubject.next(this.currentData);\r\n }\r\n\r\n private _setCurrentData() {\r\n this.currentData = getSchemaData(this.schema, this.currentData);\r\n this.currentDataHash = JSON.stringify(this.currentData);\r\n this._calculate();\r\n this.currentData = getSchemaData(this.schema, this.currentData);\r\n this.currentDataHash = JSON.stringify(this.currentData);\r\n const errors = findErrors(this.schema, this.currentData);\r\n this._lastErrors = errors && Object.keys(errors).length ? errors : null;\r\n }\r\n\r\n private _initCalculatedRefs(schema: FlexyFormLayoutSchema[]) {\r\n if (schema) {\r\n schema.forEach((schemaItem: FlexyFormFieldLayoutSchema) => {\r\n if (schemaItem.formName && schemaItem.formControl && schemaItem.calc) {\r\n this._calculatedRefs[schemaItem.formName] = {\r\n calc: schemaItem.calc,\r\n control: schemaItem.formControl as FormControl\r\n };\r\n }\r\n if (schemaItem.children) {\r\n this._initCalculatedRefs(schemaItem.children);\r\n }\r\n });\r\n }\r\n }\r\n\r\n private _calculate() {\r\n if (this._calculatedRefs) {\r\n Object.values(this._calculatedRefs).forEach(calc => {\r\n const value = calculate(calc.calc, this.currentData);\r\n if (value !== calc.control.value) {\r\n calc.control.setValue(value);\r\n calc.control.markAsDirty();\r\n }\r\n });\r\n }\r\n }\r\n\r\n private _clearHiddenData(data) {\r\n if (data[HIDDEN_CALC_GROUP_NAME]) {\r\n delete data[HIDDEN_CALC_GROUP_NAME];\r\n }\r\n }\r\n}\r\n","import { FlexyFormValidatorsMap } from './services/json-mapper.service';\r\nimport { InjectionToken } from '@angular/core';\r\n\r\nexport const FLEXY_FORM_VALIDATORS = new InjectionToken<FlexyFormValidatorsMap>('FLEXY_FORM_VALIDATORS');\r\n\r\n","import { Inject, Injectable, Optional } from '@angular/core';\r\nimport { AbstractControl, FormArray, FormBuilder, FormGroup, ValidatorFn, Validators } from '@angular/forms';\r\nimport { FlexyFormFieldLayoutSchema, FlexyFormLayoutSchema } from '../models/layout-schema.model';\r\nimport {\r\n COMPLEX_TYPE_INDEX_MARKER,\r\n FlexyFormCalcJsonSchema,\r\n FlexyFormComplexFieldLayoutJsonSchema,\r\n FlexyFormFieldLayoutJsonSchema,\r\n FlexyFormFieldType,\r\n FlexyFormIfJsonSchema,\r\n FlexyFormLayoutJson,\r\n FlexyFormLayoutJsonSchema\r\n} from '../models/layout-json-schema.model';\r\nimport { FlexyLayoutJsonMapperService, FlexyLayoutJsonSchema, FlexyLayoutSchema } from '@ng-flexy/layout';\r\nimport { cloneDeep, get, has } from 'lodash';\r\nimport { FlexyFormData } from '../models/form.data';\r\nimport { FlexyLoggerService } from '@ng-flexy/core';\r\nimport { FlexyFormsValidators } from '../validators/validators.utils';\r\nimport { FlexyValidatorsData } from '../models/validators.data';\r\nimport { FlexyForm } from '../models/form.model';\r\nimport { parseFormJson, replaceMarker } from './json-mapper.utils';\r\nimport { FLEXY_FORM_VALIDATORS } from '../form-options.token';\r\n\r\nexport interface FlexyFormValidatorsMap {\r\n [name: string]: (data?) => ValidatorFn;\r\n}\r\n\r\nconst INPUTS_READONLY_KEY = 'readonly';\r\n\r\nconst SCHEMA_CONTROL_NAME_KEY = 'name';\r\nconst SCHEMA_GROUP_KEY = 'groupKey';\r\nconst SCHEMA_COMPONENT_INPUTS_KEY = 'properties';\r\nconst SCHEMA_DEFAULT_KEY = 'default';\r\n\r\nconst DEFAULT_VALIDATORS_MAP: FlexyFormValidatorsMap = {\r\n required: () => Validators.required,\r\n maxLength: data => Validators.maxLength(data),\r\n minLength: data => Validators.minLength(data),\r\n min: data => FlexyFormsValidators.minValidator(data),\r\n max: data => FlexyFormsValidators.maxValidator(data),\r\n number: () => FlexyFormsValidators.numberValidator,\r\n integer: () => FlexyFormsValidators.integerValidator,\r\n boolean: () => FlexyFormsValidators.booleanValidator,\r\n email: () => FlexyFormsValidators.emailValidator,\r\n noWhitespace: () => FlexyFormsValidators.noWhitespaceValidator,\r\n notEmpty: () => FlexyFormsValidators.notEmptyValidator,\r\n pattern: data => Validators.pattern(data),\r\n crossField: data => FlexyFormsValidators.crossFieldValidator(data),\r\n crossFieldMin: data => FlexyFormsValidators.crossFieldMinValidator(data),\r\n crossFieldMax: data => FlexyFormsValidators.crossFieldMaxValidator(data),\r\n crossFieldAbsoluteMin: data => FlexyFormsValidators.crossFieldAbsoluteMinValidator(data),\r\n forbiddenValues: data => FlexyFormsValidators.forbiddenValuesValidator(data),\r\n arrayUniqueFields: data => FlexyFormsValidators.arrayUniqueFieldsValidator(data),\r\n minItems: data => FlexyFormsValidators.minLengthArray(data),\r\n maxItems: data => FlexyFormsValidators.maxLengthArray(data)\r\n};\r\n\r\n@Injectable({\r\n providedIn: 'root'\r\n})\r\nexport class FlexyFormJsonMapperService {\r\n static controlCounter = 0;\r\n\r\n get supportedValidators(): string[] {\r\n return Object.keys(this._validatorsMap);\r\n }\r\n\r\n private _validatorsMap = DEFAULT_VALIDATORS_MAP;\r\n\r\n constructor(\r\n @Optional() @Inject(FLEXY_FORM_VALIDATORS) validatorsMap: FlexyFormValidatorsMap,\r\n private jsonLayoutMapper: FlexyLayoutJsonMapperService,\r\n private formBuilder: FormBuilder,\r\n private logger: FlexyLoggerService\r\n ) {\r\n if (validatorsMap) {\r\n Object.assign(this._validatorsMap, validatorsMap);\r\n }\r\n }\r\n\r\n createForm(json: FlexyFormLayoutJson, readonlyMode = false, formData: FlexyFormData): FlexyForm {\r\n this.logger.debug('createForm');\r\n FlexyFormJsonMapperService.controlCounter = 0;\r\n\r\n const jsonSchema = parseFormJson(json);\r\n\r\n const rootFormGroup = new FormGroup({});\r\n const dynamicSchema: FlexyFormLayoutSchema[] = this.map(jsonSchema, readonlyMode, formData, rootFormGroup);\r\n\r\n this.logger.debug('countOfControls', FlexyFormJsonMapperService.controlCounter);\r\n\r\n return new FlexyForm(rootFormGroup, dynamicSchema, formData);\r\n }\r\n\r\n createItemControl(itemsSchema: FlexyFormLayoutJsonSchema, readonlyMode: boolean, value: FlexyFormData): AbstractControl {\r\n let control: AbstractControl;\r\n if (itemsSchema.children) {\r\n control = new FormGroup({});\r\n this.mapItem(itemsSchema, readonlyMode, value, control as FormGroup);\r\n } else {\r\n control = this.formBuilder.control(\r\n value ? value : get(itemsSchema, 'componentInputs.default'),\r\n (itemsSchema as FlexyFormFieldLayoutJsonSchema).validators\r\n ? this.mapValidators((itemsSchema as FlexyFormFieldLayoutJsonSchema).validators)\r\n : []\r\n );\r\n }\r\n return control;\r\n }\r\n\r\n createArrayItemSchema(\r\n control: AbstractControl,\r\n items: FlexyFormLayoutJsonSchema,\r\n itemKeyDef: string,\r\n parentName: string,\r\n readonlyMode: boolean,\r\n formData: FlexyFormData,\r\n value: FlexyFormData,\r\n index: number,\r\n parentSchema: FlexyFormLayoutSchema = null\r\n ): FlexyFormFieldLayoutSchema {\r\n const citems = cloneDeep(items);\r\n\r\n this.populateComplexTypeIndexMarker([citems], index + 1, value, itemKeyDef);\r\n\r\n const isComplex = citems && !!citems.children;\r\n let schema: FlexyFormLayoutSchema;\r\n\r\n if (isComplex) {\r\n const withRootValues = { ...value };\r\n const groupSchema = this._jsonLayoutItemMap({}, '' + index, parentSchema);\r\n groupSchema.children = this.map([citems], readonlyMode, withRootValues, control as FormGroup, groupSchema);\r\n\r\n schema = groupSchema;\r\n } else {\r\n schema = this.jsonLayoutMapper.map([citems])[0];\r\n (schema as FlexyFormFieldLayoutSchema).formControl = control;\r\n control.setValue(value);\r\n schema.id = parentSchema.id + ':' + index;\r\n if (!(schema as FlexyFormFieldLayoutSchema).componentInputs) {\r\n (schema as FlexyFormFieldLayoutSchema).componentInputs = {};\r\n }\r\n (schema as FlexyFormFieldLayoutSchema).componentInputs[INPUTS_READONLY_KEY] = readonlyMode;\r\n }\r\n\r\n return schema as FlexyFormFieldLayoutSchema;\r\n }\r\n\r\n createGroupItemSchema(\r\n control: AbstractControl,\r\n items: FlexyFormFieldLayoutJsonSchema,\r\n itemKeyDef: string,\r\n parentName: string,\r\n readonlyMode: boolean,\r\n formData: FlexyFormData,\r\n value: FlexyFormData,\r\n key: string,\r\n parentSchema: FlexyFormLayoutSchema = null\r\n ): FlexyFormFieldLayoutSchema {\r\n const citems = cloneDeep(items);\r\n\r\n this.populateComplexTypeIndexMarker([citems], key, value, itemKeyDef);\r\n\r\n const isComplex = citems && !!citems.children;\r\n let schema: FlexyFormFieldLayoutSchema;\r\n\r\n if (isComplex) {\r\n const withRootValues = { ...value };\r\n const groupSchema = this.map([citems], readonlyMode, withRootValues, control as FormGroup, null)[0] as FlexyFormFieldLayoutSchema;\r\n schema = groupSchema;\r\n } else {\r\n schema = this.jsonLayoutMapper.map([citems])[0] as FlexyFormFieldLayoutSchema;\r\n (schema as FlexyFormFieldLayoutSchema).formControl = control;\r\n control.setValue(value);\r\n if (!(schema as FlexyFormFieldLayoutSchema).componentInputs) {\r\n (schema as FlexyFormFieldLayoutSchema).componentInputs = {};\r\n }\r\n (schema as FlexyFormFieldLayoutSchema).componentInputs[INPUTS_READONLY_KEY] = readonlyMode;\r\n (schema as FlexyFormFieldLayoutSchema).formName = citems.name;\r\n }\r\n\r\n schema.id = (parentSchema && parentSchema.id ? parentSchema.id + ':' : '') + key;\r\n schema.groupKey = key;\r\n\r\n return schema as FlexyFormFieldLayoutSchema;\r\n }\r\n\r\n createSchema(\r\n json: FlexyFormLayoutJsonSchema[],\r\n readonlyMode = false,\r\n formData: FlexyFormData = {},\r\n parentFormGroup: FormGroup,\r\n parentControlGroupName: string,\r\n parentSchema: FlexyFormLayoutSchema = null\r\n ): FlexyFormLayoutSchema[] {\r\n const schema: FlexyFormLayoutSchema[] = [];\r\n\r\n if (json && Array.isArray(json)) {\r\n json.forEach((jsonItem, index) => {\r\n const schemaItem: FlexyFormLayoutSchema = this.mapItem(\r\n jsonItem,\r\n readonlyMode,\r\n formData,\r\n parentFormGroup,\r\n parentControlGroupName,\r\n parentSchema,\r\n '' + index\r\n );\r\n\r\n let itemParentFormGroup = parentFormGroup;\r\n let itemParentControlGroupName = parentControlGroupName;\r\n if ((schemaItem as FlexyFormFieldLayoutSchema).formControl instanceof FormGroup) {\r\n itemParentFormGroup = (schemaItem as FlexyFormFieldLayoutSchema).formControl as FormGroup;\r\n if ([FlexyFormFieldType.Group, FlexyFormFieldType.Array].includes((jsonItem as FlexyFormFieldLayoutJsonSchema).type)) {\r\n itemParentControlGroupName = this.controlComplexName(\r\n jsonItem as FlexyFormComplexFieldLayoutJsonSchema,\r\n itemParentControlGroupName\r\n );\r\n }\r\n }\r\n\r\n if (jsonItem.children) {\r\n schemaItem.children = this.createSchema(\r\n jsonItem.children,\r\n readonlyMode,\r\n formData,\r\n itemParentFormGroup,\r\n itemParentControlGroupName,\r\n schemaItem\r\n );\r\n }\r\n\r\n schema.push(schemaItem);\r\n });\r\n }\r\n\r\n return schema;\r\n }\r\n\r\n private map(\r\n json: FlexyFormLayoutJsonSchema[],\r\n readonlyMode = false,\r\n formData: FlexyFormData,\r\n parentFormGroup: FormGroup,\r\n parentSchema: FlexyFormLayoutSchema = null\r\n ): FlexyFormLayoutSchema[] {\r\n const dynamicSchema: FlexyFormLayoutSchema[] = this.createSchema(json, readonlyMode, formData, parentFormGroup, null, parentSchema);\r\n\r\n return dynamicSchema;\r\n }\r\n\r\n private createControl(config: AbstractControl | any): AbstractControl {\r\n return config instanceof AbstractControl\r\n ? config\r\n : config[1]\r\n ? this.formBuilder.control(config[0], config[1])\r\n : this.formBuilder.control(config);\r\n }\r\n\r\n private controlComplexName(jsonItem: FlexyFormComplexFieldLayoutJsonSchema, parentName: string) {\r\n return (parentName && jsonItem.name[0] === '.' ? parentName : '') + jsonItem.name;\r\n }\r\n\r\n private mapItem(\r\n jsonItem: FlexyFormLayoutJsonSchema,\r\n readonlyMode = false,\r\n formData: FlexyFormData = {},\r\n parentFormGroup: FormGroup,\r\n parentControlGroupName: string = null,\r\n parentSchema: FlexyFormLayoutSchema = null,\r\n schemaId: string = ''\r\n ): FlexyFormLayoutSchema {\r\n const formSchemaItem: FlexyFormLayoutSchema = this._jsonLayoutItemMap(jsonItem, schemaId, parentSchema);\r\n\r\n if (readonlyMode) {\r\n if (!(formSchemaItem as FlexyFormFieldLayoutSchema).componentInputs) {\r\n (formSchemaItem as FlexyFormFieldLayoutSchema).componentInputs = {};\r\n }\r\n (formSchemaItem as FlexyFormFieldLayoutSchema).componentInputs[INPUTS_READON