|
|
@ -6,13 +6,15 @@ |
|
|
*/ |
|
|
*/ |
|
|
|
|
|
|
|
|
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; |
|
|
import { FormBuilder, FormControl, FormGroup, Validators } from '@angular/forms'; |
|
|
import { debounceTimeSafe, Form, getRawValue, Types, UndefinableFormArray, UndefinableFormGroup, value$ } from '@app/framework'; |
|
|
import { debounceTimeSafe, Form, FormArrayTemplate, getRawValue, TemplatedFormArray, Types, value$ } from '@app/framework'; |
|
|
|
|
|
import { FormGroupTemplate, TemplatedFormGroup } from '@app/framework/angular/forms/templated-form-group'; |
|
|
import { BehaviorSubject, distinctUntilChanged, Observable } from 'rxjs'; |
|
|
import { BehaviorSubject, distinctUntilChanged, Observable } from 'rxjs'; |
|
|
import { AppLanguageDto } from './../services/app-languages.service'; |
|
|
import { AppLanguageDto } from './../services/app-languages.service'; |
|
|
import { LanguageDto } from './../services/languages.service'; |
|
|
import { LanguageDto } from './../services/languages.service'; |
|
|
import { FieldDto, RootFieldDto, SchemaDto, TableField } from './../services/schemas.service'; |
|
|
import { FieldDto, RootFieldDto, SchemaDto, TableField } from './../services/schemas.service'; |
|
|
import { ComponentFieldPropertiesDto, fieldInvariant } from './../services/schemas.types'; |
|
|
import { ComponentFieldPropertiesDto, fieldInvariant } from './../services/schemas.types'; |
|
|
import { AbstractContentForm, AbstractContentFormState, ComponentRulesProvider, FieldSection, FormGlobals, groupFields, PartitionConfig, RootRulesProvider, RulesProvider } from './contents.forms-helpers'; |
|
|
import { ComponentRulesProvider, RootRulesProvider, RulesProvider } from './contents.form-rules'; |
|
|
|
|
|
import { AbstractContentForm, AbstractContentFormState, FieldSection, FormGlobals, groupFields, PartitionConfig } from './contents.forms-helpers'; |
|
|
import { FieldDefaultValue, FieldsValidators } from './contents.forms.visitors'; |
|
|
import { FieldDefaultValue, FieldsValidators } from './contents.forms.visitors'; |
|
|
|
|
|
|
|
|
type SaveQueryFormType = { name: string; user: boolean }; |
|
|
type SaveQueryFormType = { name: string; user: boolean }; |
|
|
@ -150,10 +152,6 @@ export class EditContentForm extends Form<FormGroup, any> { |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public load(value: any, isInitial?: boolean) { |
|
|
public load(value: any, isInitial?: boolean) { |
|
|
for (const key of Object.keys(this.fields)) { |
|
|
|
|
|
this.fields[key].prepareLoad(value?.[key]); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
super.load(value); |
|
|
super.load(value); |
|
|
|
|
|
|
|
|
if (isInitial) { |
|
|
if (isInitial) { |
|
|
@ -238,12 +236,6 @@ export class FieldForm extends AbstractContentForm<RootFieldDto, FormGroup> { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public prepareLoad(value: any) { |
|
|
|
|
|
for (const key of Object.keys(this.partitions)) { |
|
|
|
|
|
this.partitions[key].prepareLoad(value?.[key]); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected updateCustomState(context: any, fieldData: any, itemData: any, state: AbstractContentFormState) { |
|
|
protected updateCustomState(context: any, fieldData: any, itemData: any, state: AbstractContentFormState) { |
|
|
const isRequired = state.isRequired === true; |
|
|
const isRequired = state.isRequired === true; |
|
|
|
|
|
|
|
|
@ -270,8 +262,8 @@ export class FieldForm extends AbstractContentForm<RootFieldDto, FormGroup> { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
for (const key of Object.keys(this.partitions)) { |
|
|
for (const [key, partition] of Object.entries(this.partitions)) { |
|
|
this.partitions[key].updateState(context, fieldData?.[key], itemData, state); |
|
|
partition.updateState(context, fieldData?.[key], itemData, state); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -283,14 +275,7 @@ export class FieldForm extends AbstractContentForm<RootFieldDto, FormGroup> { |
|
|
export class FieldValueForm extends AbstractContentForm<FieldDto, FormControl> { |
|
|
export class FieldValueForm extends AbstractContentForm<FieldDto, FormControl> { |
|
|
private isRequired = false; |
|
|
private isRequired = false; |
|
|
|
|
|
|
|
|
constructor( |
|
|
constructor(globals: FormGlobals, field: FieldDto, fieldPath: string, isOptional: boolean, rules: RulesProvider, partition: string) { |
|
|
globals: FormGlobals, |
|
|
|
|
|
field: FieldDto, |
|
|
|
|
|
fieldPath: string, |
|
|
|
|
|
isOptional: boolean, |
|
|
|
|
|
rules: RulesProvider, |
|
|
|
|
|
partition: string, |
|
|
|
|
|
) { |
|
|
|
|
|
super(globals, field, fieldPath, |
|
|
super(globals, field, fieldPath, |
|
|
FieldValueForm.buildControl(field, isOptional, partition, globals), |
|
|
FieldValueForm.buildControl(field, isOptional, partition, globals), |
|
|
isOptional, rules); |
|
|
isOptional, rules); |
|
|
@ -330,10 +315,10 @@ export class FieldValueForm extends AbstractContentForm<FieldDto, FormControl> { |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export class FieldArrayForm extends AbstractContentForm<FieldDto, UndefinableFormArray> { |
|
|
export class FieldArrayForm extends AbstractContentForm<FieldDto, TemplatedFormArray> { |
|
|
private readonly item$ = new BehaviorSubject<ReadonlyArray<ObjectForm>>([]); |
|
|
private readonly item$ = new BehaviorSubject<ReadonlyArray<ObjectFormBase>>([]); |
|
|
|
|
|
|
|
|
public get itemChanges(): Observable<ReadonlyArray<ObjectForm>> { |
|
|
public get itemChanges(): Observable<ReadonlyArray<ObjectFormBase>> { |
|
|
return this.item$; |
|
|
return this.item$; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -341,83 +326,42 @@ export class FieldArrayForm extends AbstractContentForm<FieldDto, UndefinableFor |
|
|
return this.item$.value; |
|
|
return this.item$.value; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public set items(value: ReadonlyArray<ObjectForm>) { |
|
|
public set items(value: ReadonlyArray<ObjectFormBase>) { |
|
|
this.item$.next(value); |
|
|
this.item$.next(value); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
constructor( |
|
|
constructor(globals: FormGlobals, field: FieldDto, fieldPath: string, isOptional: boolean, rules: RulesProvider, |
|
|
globals: FormGlobals, |
|
|
public readonly partition: string, |
|
|
field: FieldDto, |
|
|
public readonly isComponents: boolean, |
|
|
fieldPath: string, |
|
|
|
|
|
isOptional: boolean, |
|
|
|
|
|
rules: RulesProvider, |
|
|
|
|
|
private readonly partition: string, |
|
|
|
|
|
private readonly isComponents: boolean, |
|
|
|
|
|
) { |
|
|
) { |
|
|
super(globals, field, fieldPath, |
|
|
super(globals, field, fieldPath, |
|
|
FieldArrayForm.buildControl(field, isOptional), |
|
|
FieldArrayForm.buildControl(field, isOptional), |
|
|
isOptional, rules); |
|
|
isOptional, rules); |
|
|
|
|
|
|
|
|
|
|
|
this.form.template['form'] = this; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public get(index: number) { |
|
|
public get(index: number) { |
|
|
return this.items[index]; |
|
|
return this.items[index]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public addCopy(source: ObjectForm) { |
|
|
public addCopy(source: ObjectFormBase) { |
|
|
if (this.isComponents) { |
|
|
this.form.add().reset(getRawValue(source.form)); |
|
|
const child = this.createComponent(); |
|
|
|
|
|
|
|
|
|
|
|
child.load(getRawValue(source.form)); |
|
|
|
|
|
|
|
|
|
|
|
this.addChild(child); |
|
|
|
|
|
} else { |
|
|
|
|
|
const child = this.createItem(); |
|
|
|
|
|
|
|
|
|
|
|
child.load(getRawValue(source.form)); |
|
|
|
|
|
|
|
|
|
|
|
this.addChild(child); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public addComponent(schemaId?: string) { |
|
|
public addComponent(schemaId: string) { |
|
|
const child = this.createComponent(schemaId); |
|
|
this.form.add().reset({ schemaId }); |
|
|
|
|
|
|
|
|
this.addChild(child); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public addItem() { |
|
|
public addItem() { |
|
|
const child = this.createItem(); |
|
|
this.form.add(); |
|
|
|
|
|
|
|
|
this.addChild(child); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public addChild(child: ObjectForm) { |
|
|
|
|
|
this.items = [...this.items, child]; |
|
|
|
|
|
|
|
|
|
|
|
this.form.push(child.form); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public unset() { |
|
|
|
|
|
this.items = []; |
|
|
|
|
|
|
|
|
|
|
|
super.unset(); |
|
|
|
|
|
|
|
|
|
|
|
this.form.clear(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public reset() { |
|
|
|
|
|
this.items = []; |
|
|
|
|
|
|
|
|
|
|
|
this.form.clear(); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public removeItemAt(index: number) { |
|
|
public removeItemAt(index: number) { |
|
|
this.items = this.items.filter((_, i) => i !== index); |
|
|
|
|
|
|
|
|
|
|
|
this.form.removeAt(index); |
|
|
this.form.removeAt(index); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public move(index: number, item: ObjectForm) { |
|
|
public move(index: number, item: ObjectFormBase) { |
|
|
const children = [...this.items]; |
|
|
const children = [...this.items]; |
|
|
|
|
|
|
|
|
children.splice(children.indexOf(item), 1); |
|
|
children.splice(children.indexOf(item), 1); |
|
|
@ -428,86 +372,102 @@ export class FieldArrayForm extends AbstractContentForm<FieldDto, UndefinableFor |
|
|
this.sort(children); |
|
|
this.sort(children); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public sort(children: ReadonlyArray<ObjectForm>) { |
|
|
public sort(children: ReadonlyArray<ObjectFormBase>) { |
|
|
for (let i = 0; i < children.length; i++) { |
|
|
for (let i = 0; i < children.length; i++) { |
|
|
this.form.setControl(i, children[i].form); |
|
|
this.form.setControl(i, children[i].form); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public prepareLoad(value: any) { |
|
|
|
|
|
if (Types.isArray(value)) { |
|
|
|
|
|
while (this.items.length < value.length) { |
|
|
|
|
|
if (this.isComponents) { |
|
|
|
|
|
this.addComponent(); |
|
|
|
|
|
} else { |
|
|
|
|
|
this.addItem(); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
while (this.items.length > value.length) { |
|
|
|
|
|
this.removeItemAt(this.items.length - 1); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (let i = 0; i < this.items.length; i++) { |
|
|
|
|
|
this.items[i].prepareLoad(value?.[i]); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
protected updateCustomState(context: any, fieldData: any, itemData: any, state: AbstractContentFormState) { |
|
|
protected updateCustomState(context: any, fieldData: any, itemData: any, state: AbstractContentFormState) { |
|
|
for (let i = 0; i < this.items.length; i++) { |
|
|
for (let i = 0; i < this.items.length; i++) { |
|
|
this.items[i].updateState(context, fieldData?.[i], itemData, state); |
|
|
this.items[i].updateState(context, fieldData?.[i], itemData, state); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static buildControl(field: FieldDto, isOptional: boolean) { |
|
|
|
|
|
return new TemplatedFormArray(new ArrayTemplate(), FieldsValidators.create(field, isOptional)); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
class ArrayTemplate implements FormArrayTemplate { |
|
|
|
|
|
public form: FieldArrayForm; |
|
|
|
|
|
|
|
|
|
|
|
public createControl() { |
|
|
|
|
|
const child = this.form.isComponents ? |
|
|
|
|
|
this.createComponent() : |
|
|
|
|
|
this.createItem(); |
|
|
|
|
|
|
|
|
|
|
|
this.form.items = [...this.form.items, child]; |
|
|
|
|
|
|
|
|
|
|
|
return child.form; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public removeControl(index: number) { |
|
|
|
|
|
this.form.items = this.form.items.filter((_, i) => i !== index); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public clearControls() { |
|
|
|
|
|
this.form.items = []; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private createItem() { |
|
|
private createItem() { |
|
|
return new ArrayItemForm( |
|
|
return new ArrayItemForm( |
|
|
this.globals, |
|
|
this.form.globals, |
|
|
this.field as RootFieldDto, |
|
|
this.form.field as RootFieldDto, |
|
|
this.fieldPath, |
|
|
this.form.fieldPath, |
|
|
this.isOptional, |
|
|
this.form.isOptional, |
|
|
this.rules, |
|
|
this.form.rules, |
|
|
this.partition); |
|
|
this.form.partition); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
private createComponent(schemaId?: string) { |
|
|
private createComponent() { |
|
|
return new ComponentForm( |
|
|
return new ComponentForm( |
|
|
this.globals, |
|
|
this.form.globals, |
|
|
this.field as RootFieldDto, |
|
|
this.form.field as RootFieldDto, |
|
|
this.fieldPath, |
|
|
this.form.fieldPath, |
|
|
this.isOptional, |
|
|
this.form.isOptional, |
|
|
this.rules, |
|
|
this.form.rules, |
|
|
this.partition, |
|
|
this.form.partition); |
|
|
schemaId); |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
private static buildControl(field: FieldDto, isOptional: boolean) { |
|
|
export type FieldItemForm = ComponentForm | FieldValueForm | FieldArrayForm; |
|
|
const validators = FieldsValidators.create(field, isOptional); |
|
|
|
|
|
|
|
|
type FieldMap = { [name: string]: FieldItemForm }; |
|
|
|
|
|
|
|
|
return new UndefinableFormArray([], validators); |
|
|
export class ObjectFormBase<TField extends FieldDto = FieldDto> extends AbstractContentForm<TField, TemplatedFormGroup> { |
|
|
|
|
|
private readonly fieldSections$ = new BehaviorSubject<ReadonlyArray<FieldSection<FieldDto, FieldItemForm>>>([]); |
|
|
|
|
|
private readonly fields$ = new BehaviorSubject<FieldMap>({}); |
|
|
|
|
|
|
|
|
|
|
|
public get fieldSectionsChanges(): Observable<ReadonlyArray<FieldSection<FieldDto, FieldItemForm>>> { |
|
|
|
|
|
return this.fieldSections$; |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
export type FieldItemForm = ComponentForm | FieldValueForm | FieldArrayForm; |
|
|
public get fieldSections() { |
|
|
|
|
|
return this.fieldSections$.value; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
export class ObjectForm<TField extends FieldDto = FieldDto> extends AbstractContentForm<TField, UndefinableFormGroup> { |
|
|
public set fieldSections(value: ReadonlyArray<FieldSection<FieldDto, FieldItemForm>>) { |
|
|
private fields: { [key: string]: FieldItemForm } = {}; |
|
|
this.fieldSections$.next(value); |
|
|
private fieldSections: FieldSection<FieldDto, FieldItemForm>[] = []; |
|
|
} |
|
|
|
|
|
|
|
|
public get sections() { |
|
|
public get fieldsChanges(): Observable<FieldMap> { |
|
|
return this.fieldSections; |
|
|
return this.fields$; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
constructor( |
|
|
public get fields() { |
|
|
globals: FormGlobals, |
|
|
return this.fields$.value; |
|
|
field: TField, |
|
|
} |
|
|
fieldPath: string, |
|
|
|
|
|
isOptional: boolean, |
|
|
public set fields(value: FieldMap) { |
|
|
rules: RulesProvider, |
|
|
this.fields$.next(value); |
|
|
private readonly partition: string, |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
constructor(globals: FormGlobals, field: TField, fieldPath: string, isOptional: boolean, rules: RulesProvider, template: ObjectTemplate, |
|
|
|
|
|
public readonly partition: string, |
|
|
) { |
|
|
) { |
|
|
super(globals, field, fieldPath, |
|
|
super(globals, field, fieldPath, |
|
|
ObjectForm.buildControl(field, isOptional, false), |
|
|
ObjectFormBase.buildControl(template), |
|
|
isOptional, rules); |
|
|
isOptional, rules); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
@ -515,146 +475,162 @@ export class ObjectForm<TField extends FieldDto = FieldDto> extends AbstractCont |
|
|
return this.fields[field['name'] || field]; |
|
|
return this.fields[field['name'] || field]; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
protected init(schema?: ReadonlyArray<FieldDto>) { |
|
|
protected updateCustomState(context: any, fieldData: any, _: any, state: AbstractContentFormState) { |
|
|
this.fields = {}; |
|
|
for (const [key, field] of Object.entries(this.fields)) { |
|
|
this.fieldSections = []; |
|
|
field.updateState(context, fieldData?.[key], fieldData, state); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (const key of Object.keys(this.form.controls)) { |
|
|
for (const section of this.fieldSections) { |
|
|
this.form.removeControl(key); |
|
|
section.updateHidden(); |
|
|
} |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (schema) { |
|
|
private static buildControl(template: ObjectTemplate) { |
|
|
this.form.reset({}); |
|
|
return new TemplatedFormGroup(template); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (const { separator, fields } of groupFields(schema)) { |
|
|
abstract class ObjectTemplate<T extends ObjectFormBase = ObjectFormBase> implements FormGroupTemplate { |
|
|
const forms: FieldItemForm[] = []; |
|
|
private currentSchema: ReadonlyArray<FieldDto> | undefined; |
|
|
|
|
|
|
|
|
|
|
|
protected get model() { |
|
|
|
|
|
return this.modelProvider(); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
for (const field of fields) { |
|
|
constructor( |
|
|
const childForm = |
|
|
private readonly modelProvider: () => T, |
|
|
buildForm( |
|
|
) { |
|
|
this.globals, |
|
|
} |
|
|
field, |
|
|
|
|
|
this.path(field.name), |
|
|
|
|
|
this.isOptional, |
|
|
|
|
|
this.rules, |
|
|
|
|
|
this.partition); |
|
|
|
|
|
|
|
|
|
|
|
this.form.setControl(field.name, childForm.form); |
|
|
protected abstract getSchema(value: any, model: T): ReadonlyArray<FieldDto> | undefined; |
|
|
|
|
|
|
|
|
forms.push(childForm); |
|
|
public setControls(form: FormGroup, value: any) { |
|
|
|
|
|
const schema = this.getSchema(value, this.model); |
|
|
|
|
|
|
|
|
this.fields[field.name] = childForm; |
|
|
if (this.currentSchema !== schema) { |
|
|
} |
|
|
this.clearControlsCore(this.model); |
|
|
|
|
|
|
|
|
this.fieldSections.push(new FieldSection<FieldDto, FieldItemForm>(separator, forms)); |
|
|
if (schema) { |
|
|
|
|
|
this.setControlsCore(schema, value, this.model, form); |
|
|
} |
|
|
} |
|
|
} else { |
|
|
|
|
|
this.form.reset(undefined); |
|
|
this.currentSchema = schema; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public load(data: any) { |
|
|
public clearControls() { |
|
|
this.prepareLoad(data); |
|
|
if (this.currentSchema !== undefined) { |
|
|
|
|
|
this.clearControlsCore(this.model); |
|
|
this.form.reset(data); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
public prepareLoad(value: any) { |
|
|
this.currentSchema = undefined; |
|
|
for (const key of Object.keys(this.fields)) { |
|
|
|
|
|
this.fields[key].prepareLoad(value?.[key]); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
protected updateCustomState(context: any, fieldData: any, _: any, state: AbstractContentFormState) { |
|
|
protected setControlsCore(schema: ReadonlyArray<FieldDto>, value: any, model: T, form: FormGroup) { |
|
|
for (const key of Object.keys(this.fields)) { |
|
|
const fieldMap: FieldMap = {}; |
|
|
this.fields[key].updateState(context, fieldData?.[key], fieldData, state); |
|
|
const fieldSections: FieldSection<FieldDto, FieldItemForm>[] = []; |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for (const section of this.sections) { |
|
|
for (const { separator, fields } of groupFields(schema)) { |
|
|
section.updateHidden(); |
|
|
const forms: FieldItemForm[] = []; |
|
|
|
|
|
|
|
|
|
|
|
for (const field of fields) { |
|
|
|
|
|
const childForm = buildForm( |
|
|
|
|
|
model.globals, |
|
|
|
|
|
field, |
|
|
|
|
|
model.path(field.name), |
|
|
|
|
|
model.isOptional, |
|
|
|
|
|
model.rules, |
|
|
|
|
|
model.partition); |
|
|
|
|
|
|
|
|
|
|
|
form.setControl(field.name, childForm.form); |
|
|
|
|
|
|
|
|
|
|
|
forms.push(childForm); |
|
|
|
|
|
|
|
|
|
|
|
fieldMap[field.name] = childForm; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
fieldSections.push(new FieldSection<FieldDto, FieldItemForm>(separator, forms)); |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
private static buildControl(field: FieldDto, isOptional: boolean, validate: boolean) { |
|
|
model.fields = fieldMap; |
|
|
let validators = [Validators.nullValidator]; |
|
|
model.fieldSections = fieldSections; |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (validate) { |
|
|
protected clearControlsCore(model: T) { |
|
|
validators = FieldsValidators.create(field, isOptional); |
|
|
for (const name of Object.keys(model.form.controls)) { |
|
|
|
|
|
model.form.removeControl(name); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
return new UndefinableFormGroup({}, validators); |
|
|
model.fields = {}; |
|
|
|
|
|
model.fieldSections = []; |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export class ArrayItemForm extends ObjectForm<RootFieldDto> { |
|
|
export class ArrayItemForm extends ObjectFormBase<RootFieldDto> { |
|
|
constructor( |
|
|
constructor(globals: FormGlobals, field: RootFieldDto, fieldPath: string, isOptional: boolean, rules: RulesProvider, partition: string) { |
|
|
globals: FormGlobals, |
|
|
super(globals, field, fieldPath, isOptional, rules, |
|
|
field: RootFieldDto, |
|
|
new ArrayItemTemplate(() => this), partition); |
|
|
fieldPath: string, |
|
|
|
|
|
isOptional: boolean, |
|
|
|
|
|
rules: RulesProvider, |
|
|
|
|
|
partition: string, |
|
|
|
|
|
) { |
|
|
|
|
|
super(globals, field, fieldPath, isOptional, rules, partition); |
|
|
|
|
|
|
|
|
|
|
|
this.init(field.nested); |
|
|
this.form.build({}); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
export class ComponentForm extends ObjectForm { |
|
|
class ArrayItemTemplate extends ObjectTemplate<ArrayItemForm> { |
|
|
private schemaId?: string; |
|
|
public getSchema() { |
|
|
|
|
|
return this.model.field.nested; |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
public readonly properties: ComponentFieldPropertiesDto; |
|
|
export class ComponentForm extends ObjectFormBase { |
|
|
|
|
|
private readonly schema$ = new BehaviorSubject<SchemaDto | undefined>(undefined); |
|
|
|
|
|
|
|
|
public get schema() { |
|
|
public get schemaChanges(): Observable<SchemaDto | undefined> { |
|
|
return this.globals.schemas[this.schemaId!]; |
|
|
return this.schema$; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
constructor( |
|
|
public get schema() { |
|
|
globals: FormGlobals, |
|
|
return this.schema$.value; |
|
|
field: FieldDto, |
|
|
} |
|
|
fieldPath: string, |
|
|
|
|
|
isOptional: boolean, |
|
|
|
|
|
rules: RulesProvider, |
|
|
|
|
|
partition: string, |
|
|
|
|
|
schemaId?: string, |
|
|
|
|
|
) { |
|
|
|
|
|
super(globals, field, fieldPath, isOptional, |
|
|
|
|
|
new ComponentRulesProvider(fieldPath, rules), partition); |
|
|
|
|
|
|
|
|
|
|
|
this.properties = field.properties as ComponentFieldPropertiesDto; |
|
|
public set schema(value: SchemaDto | undefined) { |
|
|
|
|
|
this.schema$.next(value); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
if (schemaId) { |
|
|
public get properties() { |
|
|
this.selectSchema(schemaId); |
|
|
return this.field.properties as ComponentFieldPropertiesDto; |
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public selectSchema(schemaId?: string) { |
|
|
constructor(globals: FormGlobals, field: FieldDto, fieldPath: string, isOptional: boolean, rules: RulesProvider, partition: string) { |
|
|
if (this.schemaId !== schemaId) { |
|
|
super(globals, field, fieldPath, isOptional, |
|
|
this.schemaId = schemaId; |
|
|
new ComponentRulesProvider(fieldPath, rules, () => this.schema), |
|
|
|
|
|
new ComponentTemplate(() => this), |
|
|
|
|
|
partition); |
|
|
|
|
|
|
|
|
if (this.schema) { |
|
|
this.form.build(); |
|
|
this.rules.setSchema(this.schema); |
|
|
} |
|
|
|
|
|
|
|
|
this.init(this.schema.fields); |
|
|
public selectSchema(schemaId: string) { |
|
|
|
|
|
this.form.reset({ schemaId }); |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
this.form.setControl('schemaId', new FormControl(schemaId)); |
|
|
class ComponentTemplate extends ObjectTemplate<ComponentForm> { |
|
|
} else { |
|
|
public getSchema(value: any, model: ComponentForm) { |
|
|
this.init(undefined); |
|
|
return model.globals.schemas[value?.schemaId].fields; |
|
|
} |
|
|
|
|
|
} |
|
|
|
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public unset() { |
|
|
protected setControlsCore(schema: ReadonlyArray<FieldDto>, value: any, model: ComponentForm, form: FormGroup) { |
|
|
this.selectSchema(undefined); |
|
|
form.setControl('schemaId', new FormControl()); |
|
|
|
|
|
|
|
|
|
|
|
this.model.schema = model.globals.schemas[value?.schemaId]; |
|
|
|
|
|
|
|
|
super.unset(); |
|
|
super.setControlsCore(schema, value, model, form); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
public prepareLoad(value: any) { |
|
|
protected clearControlsCore(model: ComponentForm) { |
|
|
this.selectSchema(value?.['schemaId']); |
|
|
this.model.schema = undefined; |
|
|
|
|
|
|
|
|
super.prepareLoad(value); |
|
|
super.clearControlsCore(model); |
|
|
} |
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|