@stemy/ngx-dynamic-form 19.1.14 → 19.2.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (98) hide show
  1. package/fesm2022/stemy-ngx-dynamic-form-ui-nebular.mjs +4 -4
  2. package/fesm2022/stemy-ngx-dynamic-form-ui-nebular.mjs.map +1 -1
  3. package/fesm2022/stemy-ngx-dynamic-form.mjs +858 -1661
  4. package/fesm2022/stemy-ngx-dynamic-form.mjs.map +1 -1
  5. package/ngx-dynamic-form/common-types.d.ts +109 -26
  6. package/ngx-dynamic-form/components/dynamic-form/dynamic-form.component.d.ts +21 -0
  7. package/ngx-dynamic-form/components/dynamic-form-array/dynamic-form-array.component.d.ts +9 -0
  8. package/ngx-dynamic-form/components/dynamic-form-chips/dynamic-form-chips.component.d.ts +7 -0
  9. package/ngx-dynamic-form/components/dynamic-form-field/dynamic-form-field.component.d.ts +6 -0
  10. package/ngx-dynamic-form/components/dynamic-form-fieldset/dynamic-form-fieldset.component.d.ts +7 -0
  11. package/ngx-dynamic-form/components/dynamic-form-group/dynamic-form-group.component.d.ts +6 -0
  12. package/ngx-dynamic-form/components/dynamic-form-upload/dynamic-form-upload.component.d.ts +7 -0
  13. package/ngx-dynamic-form/directives/async-submit.directive.d.ts +17 -23
  14. package/ngx-dynamic-form/ngx-dynamic-form.imports.d.ts +5 -9
  15. package/ngx-dynamic-form/ngx-dynamic-form.module.d.ts +13 -11
  16. package/ngx-dynamic-form/services/dynamic-form-builder.service.d.ts +27 -0
  17. package/ngx-dynamic-form/services/dynamic-form.service.d.ts +28 -46
  18. package/ngx-dynamic-form/utils/customizer.d.ts +5 -12
  19. package/ngx-dynamic-form/utils/decorators.d.ts +10 -0
  20. package/ngx-dynamic-form/utils/misc.d.ts +2 -4
  21. package/ngx-dynamic-form/utils/validation.d.ts +13 -0
  22. package/package.json +21 -16
  23. package/public_api.d.ts +13 -18
  24. package/ui-nebular/index.d.ts +1 -5
  25. package/common-types.d.ts +0 -37
  26. package/components/base/dynamic-base-form-array.component.d.ts +0 -38
  27. package/components/base/dynamic-base-form-control-container.component.d.ts +0 -39
  28. package/components/base/dynamic-base-form-control.component.d.ts +0 -26
  29. package/components/base/dynamic-base-form-group.component.d.ts +0 -25
  30. package/components/base/dynamic-base-form.component.d.ts +0 -46
  31. package/components/base/dynamic-base-select.component.d.ts +0 -15
  32. package/directives/async-submit.directive.d.ts +0 -31
  33. package/esm2020/ngx-dynamic-form/common-types.mjs +0 -2
  34. package/esm2020/ngx-dynamic-form/components/base/dynamic-base-form-array.component.mjs +0 -104
  35. package/esm2020/ngx-dynamic-form/components/base/dynamic-base-form-control-container.component.mjs +0 -127
  36. package/esm2020/ngx-dynamic-form/components/base/dynamic-base-form-control.component.mjs +0 -57
  37. package/esm2020/ngx-dynamic-form/components/base/dynamic-base-form-group.component.mjs +0 -75
  38. package/esm2020/ngx-dynamic-form/components/base/dynamic-base-form.component.mjs +0 -182
  39. package/esm2020/ngx-dynamic-form/components/base/dynamic-base-select.component.mjs +0 -66
  40. package/esm2020/ngx-dynamic-form/directives/async-submit.directive.mjs +0 -116
  41. package/esm2020/ngx-dynamic-form/ngx-dynamic-form.imports.mjs +0 -26
  42. package/esm2020/ngx-dynamic-form/ngx-dynamic-form.module.mjs +0 -116
  43. package/esm2020/ngx-dynamic-form/services/dynamic-form.service.mjs +0 -615
  44. package/esm2020/ngx-dynamic-form/utils/creators.mjs +0 -67
  45. package/esm2020/ngx-dynamic-form/utils/customizer.mjs +0 -28
  46. package/esm2020/ngx-dynamic-form/utils/dynamic-editor.model.mjs +0 -14
  47. package/esm2020/ngx-dynamic-form/utils/dynamic-form-array.model.mjs +0 -128
  48. package/esm2020/ngx-dynamic-form/utils/dynamic-form-group.model.mjs +0 -26
  49. package/esm2020/ngx-dynamic-form/utils/dynamic-select.model.mjs +0 -59
  50. package/esm2020/ngx-dynamic-form/utils/form-select-subject.mjs +0 -26
  51. package/esm2020/ngx-dynamic-form/utils/form-subject.mjs +0 -29
  52. package/esm2020/ngx-dynamic-form/utils/misc.mjs +0 -47
  53. package/esm2020/ngx-dynamic-form/utils/validation-errors.mjs +0 -22
  54. package/esm2020/ngx-dynamic-form/utils/validators.mjs +0 -56
  55. package/esm2020/public_api.mjs +0 -21
  56. package/esm2020/stemy-ngx-dynamic-form.mjs +0 -5
  57. package/fesm2015/stemy-ngx-dynamic-form.mjs +0 -1927
  58. package/fesm2015/stemy-ngx-dynamic-form.mjs.map +0 -1
  59. package/fesm2020/stemy-ngx-dynamic-form.mjs +0 -1893
  60. package/fesm2020/stemy-ngx-dynamic-form.mjs.map +0 -1
  61. package/fesm2022/stemy-ngx-dynamic-form-src-ngx-dynamic-form-nebular.mjs +0 -50
  62. package/fesm2022/stemy-ngx-dynamic-form-src-ngx-dynamic-form-nebular.mjs.map +0 -1
  63. package/imports.d.ts +0 -12
  64. package/ngx-dynamic-form/components/base/dynamic-base-form-array.component.d.ts +0 -38
  65. package/ngx-dynamic-form/components/base/dynamic-base-form-control-container.component.d.ts +0 -39
  66. package/ngx-dynamic-form/components/base/dynamic-base-form-control.component.d.ts +0 -26
  67. package/ngx-dynamic-form/components/base/dynamic-base-form-group.component.d.ts +0 -25
  68. package/ngx-dynamic-form/components/base/dynamic-base-form.component.d.ts +0 -46
  69. package/ngx-dynamic-form/components/base/dynamic-base-select.component.d.ts +0 -15
  70. package/ngx-dynamic-form/services/dynamic-form-layout.service.d.ts +0 -7
  71. package/ngx-dynamic-form/utils/creators.d.ts +0 -18
  72. package/ngx-dynamic-form/utils/dynamic-editor.model.d.ts +0 -11
  73. package/ngx-dynamic-form/utils/dynamic-form-array.model.d.ts +0 -69
  74. package/ngx-dynamic-form/utils/dynamic-form-group.model.d.ts +0 -14
  75. package/ngx-dynamic-form/utils/dynamic-select.model.d.ts +0 -39
  76. package/ngx-dynamic-form/utils/form-select-subject.d.ts +0 -6
  77. package/ngx-dynamic-form/utils/form-subject.d.ts +0 -10
  78. package/ngx-dynamic-form/utils/validators.d.ts +0 -8
  79. package/ngx-dynamic-form.imports.d.ts +0 -12
  80. package/ngx-dynamic-form.module.d.ts +0 -21
  81. package/services/dynamic-form.service.d.ts +0 -61
  82. package/src/ngx-dynamic-form/nebular/imports.d.ts +0 -4
  83. package/src/ngx-dynamic-form/nebular/index.d.ts +0 -5
  84. package/src/ngx-dynamic-form/nebular/ngx-dynamic-form.nebular.module.d.ts +0 -9
  85. package/src/ngx-dynamic-form/nebular/public_api.d.ts +0 -1
  86. package/stemy-ngx-dynamic-form.d.ts +0 -5
  87. package/ui-nebular/public_api.d.ts +0 -1
  88. package/utils/creators.d.ts +0 -18
  89. package/utils/customizer.d.ts +0 -14
  90. package/utils/dynamic-editor.model.d.ts +0 -11
  91. package/utils/dynamic-form-array.model.d.ts +0 -69
  92. package/utils/dynamic-form-group.model.d.ts +0 -14
  93. package/utils/dynamic-select.model.d.ts +0 -39
  94. package/utils/form-select-subject.d.ts +0 -6
  95. package/utils/form-subject.d.ts +0 -10
  96. package/utils/misc.d.ts +0 -11
  97. package/utils/validation-errors.d.ts +0 -11
  98. package/utils/validators.d.ts +0 -8
@@ -1,324 +1,174 @@
1
- import * as i1 from '@ng-dynamic-forms/core';
2
- import { DynamicInputControlModel, DYNAMIC_FORM_CONTROL_TYPE_EDITOR, serializable, DynamicFormArrayGroupModel as DynamicFormArrayGroupModel$1, DynamicFormArrayModel as DynamicFormArrayModel$1, DynamicFormGroupModel as DynamicFormGroupModel$1, DynamicFormOption as DynamicFormOption$1, DynamicSelectModel as DynamicSelectModel$1, DynamicCheckboxModel, DynamicDatePickerModel, DynamicInputModel, DynamicTextAreaModel, DynamicFileUploadModel, DynamicFormService as DynamicFormService$1, DynamicRadioGroupModel, DynamicFormValueControlModel, isString, DynamicFormComponent, DynamicTemplateDirective, DynamicFormControlContainerComponent, DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DynamicFormArrayComponent, DynamicFormControlComponent, DynamicFormGroupComponent, DYNAMIC_FORM_CONTROL_MAP_FN, DYNAMIC_VALIDATORS } from '@ng-dynamic-forms/core';
3
- export { DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX, DYNAMIC_FORM_CONTROL_TYPE_CHECKBOX_GROUP, DYNAMIC_FORM_CONTROL_TYPE_DATEPICKER, DYNAMIC_FORM_CONTROL_TYPE_EDITOR, DYNAMIC_FORM_CONTROL_TYPE_FILE_UPLOAD, DYNAMIC_FORM_CONTROL_TYPE_GROUP, DYNAMIC_FORM_CONTROL_TYPE_INPUT, DYNAMIC_FORM_CONTROL_TYPE_RADIO_GROUP, DYNAMIC_FORM_CONTROL_TYPE_SELECT, DYNAMIC_FORM_CONTROL_TYPE_TEXTAREA, DynamicCheckboxGroupModel, DynamicCheckboxModel, DynamicDatePickerModel, DynamicFileUploadModel, DynamicFormControlComponent, DynamicFormControlModel, DynamicFormsCoreModule, DynamicInputModel, DynamicListDirective, DynamicRadioGroupModel, DynamicTemplateDirective, DynamicTextAreaModel } from '@ng-dynamic-forms/core';
4
1
  import * as i2 from '@stemy/ngx-utils';
5
- import { ObjectUtils, TimerUtils, cachedFactory, StringUtils, OpenApiService, ObservableUtils, TOASTER_SERVICE, EventsService, NgxUtilsModule } from '@stemy/ngx-utils';
6
- import { __decorate } from 'tslib';
7
- import { BehaviorSubject, isObservable, of, Subject, firstValueFrom, Subscription } from 'rxjs';
8
- import { map, debounceTime, first, groupBy, mergeMap } from 'rxjs/operators';
2
+ import { cachedFactory, ReflectUtils, ObjectUtils, LANGUAGE_SERVICE, API_SERVICE, StringUtils, TOASTER_SERVICE, NgxUtilsModule } from '@stemy/ngx-utils';
9
3
  import * as i0 from '@angular/core';
10
- import { Injector, Injectable, Inject, EventEmitter, Directive, Input, Output, HostBinding, HostListener, QueryList, Component, ChangeDetectionStrategy, ContentChildren, ViewChildren, ViewContainerRef, ViewChild, forwardRef, Optional, makeEnvironmentProviders, NgModule } from '@angular/core';
11
- import { FormGroup, FormArray, FormsModule, ReactiveFormsModule, NG_VALIDATORS } from '@angular/forms';
4
+ import { Inject, Injectable, input, output, inject, Renderer2, ElementRef, computed, signal, effect, HostListener, HostBinding, Directive, resource, Injector, ChangeDetectionStrategy, ViewEncapsulation, Component, makeEnvironmentProviders, NgModule } from '@angular/core';
5
+ import { startWith, distinctUntilChanged, switchMap, first, from, isObservable, firstValueFrom } from 'rxjs';
6
+ import * as i1 from '@angular/forms';
7
+ import { FormGroup as FormGroup$1, FormArray as FormArray$1, FormsModule, ReactiveFormsModule } from '@angular/forms';
8
+ import { outputToObservable, rxResource } from '@angular/core/rxjs-interop';
9
+ import { debounceTime } from 'rxjs/operators';
10
+ import * as i3 from '@ngx-formly/core';
11
+ import { FieldArrayType, FieldType, FieldWrapper, FormlyModule } from '@ngx-formly/core';
12
+ import * as i1$1 from '@angular/common';
12
13
  import { CommonModule } from '@angular/common';
13
14
 
14
- class DynamicEditorModel extends DynamicInputControlModel {
15
- type = DYNAMIC_FORM_CONTROL_TYPE_EDITOR;
16
- inputType;
17
- convertObject;
18
- constructor(config, layout) {
19
- super(config, layout);
20
- this.inputType = config.inputType || "javascript";
21
- this.convertObject = config.convertObject !== false;
22
- }
15
+ // --- Basic frm constants ---
16
+ const FORM_ROOT_KEY = "__root";
17
+
18
+ function customizeFormField(...providers) {
19
+ const factory = cachedFactory(providers);
20
+ return async (property, schema, config, parent, options, injector) => {
21
+ const customizers = factory(injector);
22
+ const configs = [config];
23
+ for (const customizer of customizers) {
24
+ const index = configs.findIndex(m => customizer.acceptField(m, parent));
25
+ if (index >= 0) {
26
+ const custom = await customizer.customizeField(configs[index], property, schema, parent, options);
27
+ const result = Array.isArray(custom) ? custom : [custom];
28
+ configs.splice(index, 1, ...result);
29
+ }
30
+ }
31
+ return configs;
32
+ };
23
33
  }
24
- __decorate([
25
- serializable()
26
- ], DynamicEditorModel.prototype, "type", void 0);
27
34
 
28
- class DynamicFormArrayGroupModel extends DynamicFormArrayGroupModel$1 {
29
- context;
30
- get hidden() {
31
- return this.isHidden;
32
- }
33
- set hidden(value) {
34
- if (this.isHidden == value)
35
- return;
36
- this.isHidden = value || false;
37
- this.context?.filterGroups();
38
- }
39
- isHidden;
40
- constructor(context, group, index = -1) {
41
- super(context, group, index);
42
- this.context = context;
43
- this.isHidden = false;
44
- }
35
+ function defineFormControl(target, propertyKey, cb) {
36
+ const fields = ReflectUtils.getMetadata("dynamicFormFields", target) || new Set();
37
+ const existing = ReflectUtils.getMetadata("dynamicFormField", target, propertyKey);
38
+ const builder = !ObjectUtils.isFunction(existing) ? cb : ((fb, opts, path) => {
39
+ const data = existing(fb, opts, path);
40
+ return ObjectUtils.assign(data || {}, cb(fb, opts, path) || {});
41
+ });
42
+ fields.add(propertyKey);
43
+ ReflectUtils.defineMetadata("dynamicFormField", builder, target, propertyKey);
44
+ ReflectUtils.defineMetadata("dynamicFormFields", fields, target);
45
45
  }
46
- class DynamicFormArrayModel extends DynamicFormArrayModel$1 {
47
- config;
48
- filteredGroups;
49
- sortable;
50
- useTabs;
51
- saveTab;
52
- restoreTab;
53
- getTabLabel;
54
- additional;
55
- groups = [];
56
- tabIndex = 0;
57
- _sortBy;
58
- _sortDescending;
59
- _formArray;
60
- _filteredGroups;
61
- _filterTimer;
62
- get addItem() {
63
- return this.config.addItem !== false;
64
- }
65
- get insertItem() {
66
- return !this._sortBy && this.config.insertItem !== false;
67
- }
68
- get cloneItem() {
69
- return this.config.cloneItem !== false;
70
- }
71
- get moveItem() {
72
- return !this._sortBy && this.config.moveItem !== false;
73
- }
74
- get removeItem() {
75
- return this.config.removeItem !== false;
76
- }
77
- get clearItems() {
78
- return this.config.clearItems !== false;
79
- }
80
- get sortBy() {
81
- return this._sortBy;
82
- }
83
- set sortBy(value) {
84
- if (!this.sortable)
85
- return;
86
- value = value || null;
87
- if (this._sortBy !== value) {
88
- this._sortBy = value;
89
- this._sortDescending = false;
90
- }
91
- else if (this._sortDescending) {
92
- this._sortBy = null;
93
- this._sortDescending = false;
94
- }
95
- else {
96
- this._sortDescending = true;
46
+ function FormSerializable(serializer) {
47
+ return (target, key) => {
48
+ defineFormControl(target, key, () => ({ key, serializer, serialize: true }));
49
+ };
50
+ }
51
+ function FormInput(data) {
52
+ return (target, key) => {
53
+ const meta = ReflectUtils.getOwnMetadata("design:type", target, key);
54
+ const type = meta ? meta.name : "";
55
+ let inputType = key.indexOf("password") < 0 ? "text" : "password";
56
+ switch (type) {
57
+ case "Number":
58
+ inputType = "number";
59
+ break;
60
+ case "Boolean":
61
+ inputType = "checkbox";
62
+ break;
97
63
  }
98
- this.filterGroups();
99
- }
100
- get sortDescending() {
101
- return this._sortDescending;
102
- }
103
- get sortOrder() {
104
- return this.sortDescending ? "desc" : "asc";
105
- }
106
- constructor(config, layout) {
107
- super(config, layout);
108
- this.config = config;
109
- this.filteredGroups = new BehaviorSubject([]);
110
- this.sortable = config.sortable || false;
111
- this.useTabs = config.useTabs || false;
112
- this.saveTab = ObjectUtils.isFunction(config.saveTab) ? config.saveTab : ((index, model, arrayModel) => {
113
- arrayModel.tabIndex = index;
114
- });
115
- this.restoreTab = ObjectUtils.isFunction(config.restoreTab) ? config.restoreTab : ((model) => {
116
- return model.tabIndex;
64
+ data.type = data.type || inputType;
65
+ defineFormControl(target, key, (fb, path, options) => fb.createFormInput(key, data, path, options));
66
+ };
67
+ }
68
+ function FormSelect(data) {
69
+ return (target, key) => {
70
+ defineFormControl(target, key, (fb, path, options) => fb.createFormSelect(key, data, path, options));
71
+ };
72
+ }
73
+ function FormUpload(data) {
74
+ return (target, key) => {
75
+ defineFormControl(target, key, (fb, path, options) => fb.createFormUpload(key, data, path, options));
76
+ };
77
+ }
78
+ function FormFile(data) {
79
+ console.warn(`@FormFile decorator is deprecated, use @FormUpload instead`);
80
+ return FormUpload(data);
81
+ }
82
+ function FormGroup(data) {
83
+ return (target, key) => {
84
+ defineFormControl(target, key, (fb, path, options) => {
85
+ const targetType = ReflectUtils.getOwnMetadata("design:type", target, key);
86
+ return fb.resolveFormGroup(key, targetType, data, path, options);
117
87
  });
118
- this.getTabLabel = ObjectUtils.isFunction(config.getTabLabel) ? config.getTabLabel : ((index) => {
119
- return `${index + 1}`;
88
+ };
89
+ }
90
+ function FormArray(itemType, data) {
91
+ return (target, key) => {
92
+ defineFormControl(target, key, (fb, path, options) => {
93
+ return fb.resolveFormArray(key, itemType, data, path, options);
120
94
  });
121
- this.additional = config.additional || {};
122
- this.tabIndex = 0;
123
- this._sortBy = null;
124
- this._sortDescending = false;
125
- this._formArray = null;
126
- }
127
- initialize(array) {
128
- this._formArray = array || this._formArray;
129
- this.filterGroups();
130
- }
131
- filterGroups() {
132
- this._filterTimer = this._filterTimer || TimerUtils.createTimeout();
133
- this._filterTimer.set(() => {
134
- const filtered = this.groups.filter(g => !g.hidden);
135
- if (this._sortBy && this._formArray) {
136
- const compare = this._sortDescending
137
- ? (a, b) => this.compareModels(b, a)
138
- : (a, b) => this.compareModels(a, b);
139
- filtered.sort(compare);
140
- }
141
- this._filteredGroups = filtered;
142
- this.filteredGroups.next(filtered);
143
- }, 100);
144
- }
145
- getFiltered(index) {
146
- return !this._filteredGroups ? null : this._filteredGroups[index];
147
- }
148
- insertGroup(index) {
149
- const group = new DynamicFormArrayGroupModel(this, this.groupFactory());
150
- this.groups.splice(index, 0, group);
151
- this.groups.forEach((g, index) => g.index = index);
152
- this.filterGroups();
153
- return group;
154
- }
155
- moveGroup(index, step) {
156
- super.moveGroup(index, step);
157
- this.filterGroups();
158
- }
159
- removeGroup(index) {
160
- super.removeGroup(index);
161
- this.filterGroups();
162
- }
163
- compareModels(a, b) {
164
- const aGroup = this._formArray.at(a.index).get(this._sortBy)?.value || null;
165
- const bGroup = this._formArray.at(b.index).get(this._sortBy)?.value || null;
166
- return ObjectUtils.compare(aGroup, bGroup);
167
- }
95
+ };
168
96
  }
169
-
170
- class DynamicFormGroupModel extends DynamicFormGroupModel$1 {
171
- groups;
172
- constructor(config, layout) {
173
- super(config, layout);
174
- const controls = [...config.group];
175
- const groups = [];
176
- const sets = config.fieldSets || [];
177
- for (const fs of sets) {
178
- const fields = [];
179
- for (const f of fs.fields) {
180
- const ix = controls.findIndex(c => c.id === f);
181
- if (ix < 0)
182
- continue;
183
- fields.push(controls.splice(ix, 1)[0]);
184
- }
185
- if (fields.length === 0)
186
- continue;
187
- groups.push({ id: fs.id, legend: fs.legend, fields });
188
- }
189
- if (controls.length > 0) {
190
- groups.unshift({ id: "root-controls", legend: config.legend, fields: controls });
191
- }
192
- this.groups = groups;
193
- }
97
+ function FormModel(data) {
98
+ console.warn(`@FormModel decorator is deprecated, use @FormGroup instead`);
99
+ return FormGroup(data);
194
100
  }
195
101
 
196
- const ignoredKeys = ["disabled", "label", "value", "classes"];
197
- class DynamicFormOption extends DynamicFormOption$1 {
198
- classes;
199
- props;
200
- constructor(config) {
201
- super(config);
202
- this.classes = config.classes || "";
203
- this.props = Object.keys(config).reduce((res, k) => {
204
- if (ignoredKeys.indexOf(k) >= 0)
205
- return res;
206
- res[k] = config[k];
207
- return res;
208
- }, {});
209
- }
102
+ function validationMessage(injector, key, labelPrefix) {
103
+ const language = injector.get(LANGUAGE_SERVICE);
104
+ return (_, field) => {
105
+ return language.getTranslationSync(labelPrefix ? `${labelPrefix}.error.${key}` : `error.${key}`, field);
106
+ };
210
107
  }
211
- class DynamicSelectModel extends DynamicSelectModel$1 {
212
- groupBy;
213
- inline;
214
- getClasses;
215
- allowEmpty;
216
- options$ = null;
217
- mOptions = [];
218
- constructor(config, layout) {
219
- super(config, layout);
220
- this.groupBy = config.groupBy || null;
221
- this.inline = config.inline || false;
222
- this.getClasses = ObjectUtils.isFunction(config.getClasses) ? config.getClasses : (() => "");
223
- this.allowEmpty = config.allowEmpty || false;
224
- this.options = config.options;
225
- }
226
- set options(options) {
227
- if (Array.isArray(options)) {
228
- this.mOptions = options.map(optionConfig => new DynamicFormOption(optionConfig));
229
- this.updateOptions();
230
- }
231
- else if (isObservable(options)) {
232
- this.options$ = options.pipe(map(optionsConfig => {
233
- this.mOptions = optionsConfig.map(optionConfig => new DynamicFormOption(optionConfig));
234
- return this.mOptions;
235
- }));
236
- }
237
- else {
238
- this.updateOptions();
239
- }
240
- }
241
- get options() {
242
- return this.mOptions;
243
- }
244
- insert(index, optionConfig) {
245
- const option = new DynamicFormOption(optionConfig);
246
- this.mOptions.splice(index, 0, option);
247
- this.updateOptions();
248
- return option;
249
- }
250
- remove(...indices) {
251
- indices.forEach(index => this.mOptions.splice(index, 1));
252
- this.updateOptions();
253
- }
254
- updateOptions() {
255
- this.options$ = of(this.mOptions);
256
- }
108
+ function withName(fn, name) {
109
+ fn.validatorName = name;
110
+ return fn;
257
111
  }
258
-
259
- function createFormConfig(id, config) {
260
- const res = (config || { id });
261
- res.id = id;
262
- res.label = ObjectUtils.isNullOrUndefined(config.label) ? id : config.label;
263
- res.disabled = config.disabled || false;
264
- res.hidden = config.hidden || false;
265
- res.additional = Object.assign({
266
- // For material components
267
- appearance: "fill",
268
- }, res.additional || {});
269
- return res;
112
+ function validateEach(each, cb, name) {
113
+ return withName((control) => {
114
+ const value = control.value;
115
+ return each ? Array.isArray(value) && value.every(cb) : cb(value);
116
+ }, name);
270
117
  }
271
- function createFormCheckbox(id, config, layout) {
272
- const res = createFormConfig(id, config);
273
- res.indeterminate = config.indeterminate || false;
274
- return new DynamicCheckboxModel(res, layout);
118
+ function jsonValidation() {
119
+ return withName((control) => {
120
+ const value = control.value;
121
+ if (!value)
122
+ return false;
123
+ try {
124
+ JSON.parse(value);
125
+ return true;
126
+ }
127
+ catch (e) {
128
+ return false;
129
+ }
130
+ }, "json");
275
131
  }
276
- function createFormDate(id, config, layout) {
277
- const res = createFormConfig(id, config);
278
- res.autoFocus = config.autoFocus || false;
279
- res.focusedDate = config.focusedDate || new Date();
280
- res.inline = config.inline || false;
281
- return new DynamicDatePickerModel(res, layout);
132
+ function requiredValidation() {
133
+ return withName((control) => ObjectUtils.isString(control.value) ? control.value.length > 0 : ObjectUtils.isDefined(control.value), "required");
282
134
  }
283
- function createFormEditor(id, config, layout) {
284
- const res = createFormConfig(id, config);
285
- return new DynamicEditorModel(res, layout);
135
+ function translationValidation(langs = ["de", "en"]) {
136
+ return withName((control) => {
137
+ const value = control.value;
138
+ if (!value || value.length == 0)
139
+ return false;
140
+ return value.findIndex(t => langs.includes(t.lang) && !t.translation) < 0;
141
+ }, "translation");
286
142
  }
287
- function createFormArray(id, config, layout) {
288
- const res = createFormConfig(id, config);
289
- return new DynamicFormArrayModel(res, layout);
143
+ function phoneValidation() {
144
+ return withName((control) => {
145
+ const value = control.value;
146
+ if (!value)
147
+ return true;
148
+ const phoneRegexp = /^\d{10,12}$/;
149
+ return phoneRegexp.test(value);
150
+ }, "phone");
290
151
  }
291
- function createFormGroup(id, config, layout) {
292
- const res = createFormConfig(id, config);
293
- res.name = config.name || "";
294
- return new DynamicFormGroupModel(res, layout);
152
+ function emailValidation() {
153
+ return withName((control) => {
154
+ const value = control.value;
155
+ if (!value)
156
+ return true;
157
+ const emailRegexp = /^[\w-.]+@([\w-]+\.)+[\w-]{2,4}$/g;
158
+ return emailRegexp.test(value);
159
+ }, "email");
295
160
  }
296
- function createFormInput(id, config, type = "text", layout) {
297
- const res = createFormConfig(id, config);
298
- res.inputType = config.inputType || type;
299
- res.placeholder = config.placeholder || (config.inputType == "mask" ? "_" : "");
300
- res.step = config.step || 1;
301
- res.mask = config.mask || null;
302
- return new DynamicInputModel(res, layout);
161
+ function minLengthValidation(minLength, each) {
162
+ return validateEach(each, v => typeof v == "string" && v.length >= minLength, "minLength");
303
163
  }
304
- function createFormSelect(id, config, layout) {
305
- const res = createFormConfig(id, config);
306
- res.options = config.options || [];
307
- return new DynamicSelectModel(res, layout);
164
+ function maxLengthValidation(maxLength, each) {
165
+ return validateEach(each, v => typeof v == "string" && v.length <= maxLength, "maxLength");
308
166
  }
309
- function createFormTextarea(id, config, layout) {
310
- const res = createFormConfig(id, config);
311
- res.cols = config.cols || 10;
312
- res.rows = config.rows || 3;
313
- res.wrap = config.wrap || "soft";
314
- return new DynamicTextAreaModel(res, layout);
167
+ function minValueValidation(min, each) {
168
+ return validateEach(each, v => typeof v == "number" && v >= min, "minValue");
315
169
  }
316
- function createFormFile(id, config, layout) {
317
- const res = createFormConfig(id, config);
318
- res.accept = config.accept || ["jpg", "jpeg", "png"];
319
- res.multiple = config.multiple || false;
320
- res.url = ObjectUtils.isString(config.url) ? config.url : "assets";
321
- return new DynamicFileUploadModel(res, layout);
170
+ function maxValueValidation(max, each) {
171
+ return validateEach(each, v => typeof v == "number" && v <= max, "maxValue");
322
172
  }
323
173
 
324
174
  function isStringWithVal(val) {
@@ -333,11 +183,11 @@ function findRefs(property) {
333
183
  function replaceSpecialChars(str, to = "-") {
334
184
  return `${str}`.replace(/[&\/\\#, +()$~%.@'":*?<>{}]/g, to);
335
185
  }
336
- function mergeFormModels(formModels) {
186
+ function mergeFormFields(formFields) {
337
187
  const res = [];
338
- for (const formModel of formModels) {
188
+ for (const formModel of formFields) {
339
189
  for (const subModel of formModel) {
340
- const index = res.findIndex(t => t.id == subModel.id);
190
+ const index = res.findIndex(t => t.key == subModel.key);
341
191
  if (index >= 0) {
342
192
  res[index] = subModel;
343
193
  continue;
@@ -347,176 +197,263 @@ function mergeFormModels(formModels) {
347
197
  }
348
198
  return res;
349
199
  }
350
- function collectPathAble(start, getter) {
351
- if (!start || !getter(start))
352
- return [];
353
- const parts = [];
354
- let currentPath = start;
355
- while (currentPath) {
356
- const val = getter(currentPath);
357
- if (val) {
358
- parts.unshift(val);
359
- }
360
- currentPath = currentPath.parent;
361
- }
362
- return parts;
363
- }
364
- function getDynamicPath(start) {
365
- return collectPathAble(start, t => t.id).join(".");
366
- }
367
200
  const MIN_INPUT_NUM = -999999999;
368
201
  const MAX_INPUT_NUM = 999999999;
369
202
  const EDITOR_FORMATS = ["php", "json", "html", "css", "scss"];
370
203
 
371
- function getFormComponent(...providers) {
372
- const factory = cachedFactory(providers);
373
- return (model, injector) => {
374
- const customizers = factory(injector);
375
- for (const customizer of customizers) {
376
- const component = customizer.acceptModel(model, getDynamicPath(model)) ? customizer.getFormComponent(model) : null;
377
- if (component) {
378
- return component;
204
+ class DynamicFormBuilderService {
205
+ injector;
206
+ api;
207
+ language;
208
+ constructor(injector, api, language) {
209
+ this.injector = injector;
210
+ this.api = api;
211
+ this.language = language;
212
+ }
213
+ getLabel(key, label, parent, options) {
214
+ const labelPrefix = !ObjectUtils.isString(options.labelPrefix) ? `` : options.labelPrefix;
215
+ const pathPrefix = `${parent?.props?.label || labelPrefix}`;
216
+ const labelItems = ObjectUtils.isString(label)
217
+ ? (!label ? [] : [labelPrefix, label])
218
+ : [pathPrefix, `${key || ""}`];
219
+ return labelItems.filter(l => l.length > 0).join(".");
220
+ }
221
+ createFormField(key, type, data, props, parent, options) {
222
+ const validators = Array.isArray(data.validators)
223
+ ? data.validators.reduce((res, validator, ix) => {
224
+ res[validator.validatorName || `validator_${ix}`] = validator;
225
+ return res;
226
+ }, {})
227
+ : data.validators || {};
228
+ return {
229
+ key,
230
+ type,
231
+ validators,
232
+ parent,
233
+ className: Array.isArray(data.classes) ? data.classes.join(" ") : data.classes || "",
234
+ hide: data.hidden === true,
235
+ fieldSet: String(data.fieldSet || ""),
236
+ validation: {
237
+ messages: Object.keys(validators).reduce((res, key) => {
238
+ res[key] = validationMessage(this.injector, key, options.labelPrefix);
239
+ return res;
240
+ }, {})
241
+ },
242
+ props: {
243
+ ...props,
244
+ formCheck: "nolabel",
245
+ required: !!validators.required,
246
+ label: this.getLabel(key, data.label, parent, options),
379
247
  }
380
- }
381
- return null;
382
- };
383
- }
384
- function customizeFormModel(...providers) {
385
- const factory = cachedFactory(providers);
386
- return async (property, schema, model, config, path, injector) => {
387
- const customizers = factory(injector);
388
- const models = [model];
389
- for (const customizer of customizers) {
390
- const index = models.findIndex(m => customizer.acceptModel(m, path));
391
- if (index >= 0) {
392
- const custom = await customizer.customizeModel(models[index], config, property, schema, path);
393
- const result = Array.isArray(custom) ? custom : [custom];
394
- models.splice(index, 1, ...result);
248
+ };
249
+ }
250
+ resolveFormFields(target, parent, options) {
251
+ const prototype = target?.prototype || {};
252
+ const fields = ReflectUtils.getMetadata("dynamicFormFields", target?.prototype || {}) || new Set();
253
+ const result = [];
254
+ for (const key of fields) {
255
+ const builder = ReflectUtils.getMetadata("dynamicFormField", prototype, key);
256
+ const field = builder(this, parent, options);
257
+ if (field) {
258
+ result.push(field);
395
259
  }
396
260
  }
397
- return models;
398
- };
399
- }
400
-
401
- function validateJSON(control) {
402
- const value = control.value;
403
- if (!value)
404
- return null;
405
- try {
406
- JSON.parse(value);
407
- return null;
408
- }
409
- catch (e) {
410
- return { json: true };
411
- }
412
- }
413
- function validateRequiredTranslation(control) {
414
- const value = control.value;
415
- if (!value || value.length == 0)
416
- return { requiredTranslation: true };
417
- return value.findIndex(t => (t.lang == "de" || t.lang == "en") && !t.translation) < 0
418
- ? null
419
- : { requiredTranslation: true };
420
- }
421
- function validatePhone(control) {
422
- const value = control.value;
423
- if (!value)
424
- return Promise.resolve(null);
425
- const phoneRegexp = /^(?:\d){10,12}$/;
426
- return phoneRegexp.test(value) ? null : { phone: true };
427
- }
428
- function validateItemsMinLength(minLength) {
429
- return (control) => {
430
- const value = control.value;
431
- return (Array.isArray(value) && value.every(v => typeof v == "string" && v.length >= minLength))
432
- ? null : { itemsMinLength: minLength };
433
- };
434
- }
435
- function validateItemsMaxLength(maxLength) {
436
- return (control) => {
437
- const value = control.value;
438
- return (Array.isArray(value) && value.every(v => typeof v == "string" && v.length <= maxLength))
439
- ? null : { itemsMaxLength: maxLength };
440
- };
441
- }
442
- function validateItemsMinValue(min) {
443
- return (control) => {
444
- const value = control.value;
445
- return (Array.isArray(value) && value.every(v => typeof v == "number" && v >= min))
446
- ? null : { itemsMinValue: min };
447
- };
448
- }
449
- function validateItemsMaxValue(max) {
450
- return (control) => {
451
- const value = control.value;
452
- return (Array.isArray(value) && value.every(v => typeof v == "number" && v <= max))
453
- ? null : { itemsMaxValue: max };
454
- };
455
- }
456
-
457
- const indexLabels = ["$ix", "$pix"];
458
- class FormSubject extends Subject {
459
- notifyCallback;
460
- constructor(notifyCallback) {
461
- super();
462
- this.notifyCallback = notifyCallback;
261
+ return this.createFieldSets(result, parent, options);
463
262
  }
464
- handleNotifiedValue(controlModel, control, val) {
465
- val.then(v => this.next(v));
263
+ resolveFormGroup(key, target, data, parent = null, options = {}) {
264
+ return this.createFormGroup(key, sp => this.resolveFormFields(target, sp, options), data, parent, options);
466
265
  }
467
- notify(controlModel, control, root) {
468
- const indexes = {};
469
- let path = controlModel;
470
- let ix = 0;
471
- while (path) {
472
- if (!isNaN(path.index)) {
473
- const key = indexLabels[ix++] || `$pix${ix}`;
474
- indexes[key] = path.index;
475
- }
476
- path = path.parent;
477
- }
478
- let value = this.notifyCallback(controlModel, control, root, indexes);
479
- if (!(value instanceof Promise)) {
480
- value = Promise.resolve(value);
481
- }
482
- this.handleNotifiedValue(controlModel, control, value);
266
+ resolveFormArray(key, itemType, data, parent = null, options = {}) {
267
+ return this.createFormArray(key, sp => {
268
+ return typeof itemType === "function" ? this.resolveFormFields(itemType, sp, options) : this.createFormInput("", typeof itemType === "string" ? { type: `${itemType}` } : itemType, null, options);
269
+ }, data, parent, options);
483
270
  }
484
- }
485
-
486
- class FormSelectSubject extends FormSubject {
487
- handleNotifiedValue(controlModel, control, val) {
488
- val.then(options => {
489
- if (options.length == 0) {
490
- this.next(options);
491
- return;
271
+ createFieldSets(fields, parent, options) {
272
+ const others = [];
273
+ const groups = {};
274
+ for (const field of fields) {
275
+ const fsName = field.hide ? null : String(field.fieldSet || "");
276
+ // If we have a fieldset name defined and have actual fields for it
277
+ // then push the property fields into a group
278
+ if (fsName) {
279
+ const group = groups[fsName] || [];
280
+ groups[fsName] = group;
281
+ group.push(field);
282
+ continue;
492
283
  }
493
- const currentVal = control.value;
494
- if (controlModel.multiple) {
495
- const correctVal = (currentVal || []).filter(t => options.findIndex(o => o.value == t) >= 0);
496
- if (correctVal.length !== currentVal?.length) {
497
- control.setValue(correctVal, { onlySelf: true, emitEvent: false });
284
+ // Otherwise just push the fields to the others
285
+ others.push(field);
286
+ }
287
+ // Create a field-set wrapper for each group and concat the other fields to the end
288
+ return Object.keys(groups).map(group => {
289
+ return {
290
+ fieldGroup: groups[group],
291
+ wrappers: ["form-fieldset"],
292
+ id: !parent ? group : `${parent.props?.label}.${group}`,
293
+ props: {
294
+ label: this.getLabel(group, group, parent, options),
295
+ hidden: false
498
296
  }
297
+ };
298
+ }).concat(others);
299
+ }
300
+ createFormInput(key, data, parent, options) {
301
+ data = data || {};
302
+ return this.createFormField(key, data.type === "checkbox" ? "checkbox" : "input", data, {
303
+ type: `${data.type || "text"}`,
304
+ pattern: ObjectUtils.isString(data.pattern) ? data.pattern : "",
305
+ step: data.step,
306
+ cols: data.cols || null,
307
+ rows: data.rows || 10,
308
+ min: isNaN(data.min) ? MIN_INPUT_NUM : data.min,
309
+ max: isNaN(data.max) ? MAX_INPUT_NUM : data.max,
310
+ minLength: isNaN(data.minLength) ? 0 : data.minLength,
311
+ maxLength: isNaN(data.maxLength) ? MAX_INPUT_NUM : data.maxLength,
312
+ placeholder: data.placeholder || "",
313
+ attributes: {
314
+ autocomplete: data.autocomplete || "off"
315
+ },
316
+ }, parent, options);
317
+ }
318
+ createFormSelect(key, data, parent, options) {
319
+ data = data || { options: () => [] };
320
+ const select = this.createFormField(key, data.type === "radio" ? "radio" : "select", data, {
321
+ multiple: data.multiple,
322
+ type: data.type,
323
+ groupBy: data.groupBy,
324
+ inline: data.inline,
325
+ allowEmpty: data.allowEmpty
326
+ }, parent, options);
327
+ select.hooks = {
328
+ onInit: field => {
329
+ const options = data.options(field);
330
+ const control = field.formControl.root;
331
+ field.props.options = options instanceof Promise ? control.valueChanges.pipe(startWith(control.value), distinctUntilChanged(), switchMap(async () => {
332
+ const results = await data.options(field);
333
+ return this.fixSelectOptions(field, results);
334
+ })) : options;
499
335
  }
500
- else {
501
- const option = options.find(t => t.value == currentVal);
502
- if (!option) {
503
- control.setValue(controlModel.allowEmpty ? null : options[0]?.value ?? null, { onlySelf: true, emitEvent: false });
504
- }
336
+ };
337
+ return select;
338
+ }
339
+ createFormUpload(key, data, parent, options) {
340
+ data = data || {};
341
+ if (data.asFile) {
342
+ data.inline = true;
343
+ console.warn(`File upload property "asFile" is deprecated. Use "inline" instead.`);
344
+ }
345
+ if (data.multi) {
346
+ data.multiple = true;
347
+ console.warn(`File upload property "multi" is deprecated. Use "multiple" instead.`);
348
+ }
349
+ return this.createFormField(key, "upload", data, {
350
+ inline: data.inline === true,
351
+ multiple: data.multiple === true,
352
+ accept: data.accept || [".png", ".jpg"],
353
+ url: data.url?.startsWith("http") ? data.url : this.api.url(data.url || "assets"),
354
+ maxSize: isNaN(data.maxSize) ? MAX_INPUT_NUM : data.maxSize,
355
+ uploadOptions: data.uploadOptions || {},
356
+ createUploadData: data.createUploadData
357
+ }, parent, options);
358
+ }
359
+ createFormGroup(key, fields, data, parent, options) {
360
+ data = data || {};
361
+ const group = this.createFormField(key, undefined, data, {}, parent, options);
362
+ group.wrappers = ["form-group"];
363
+ const result = fields(group);
364
+ const handleGroup = (fieldGroup) => {
365
+ group.fieldGroup = fieldGroup;
366
+ return group;
367
+ };
368
+ return result instanceof Promise
369
+ ? result.then(handleGroup)
370
+ : handleGroup(result);
371
+ }
372
+ createFormArray(key, fields, data, parent, options) {
373
+ data = data || {};
374
+ const array = this.createFormField(key, "array", data, {
375
+ // initialCount: data.initialCount || 0,
376
+ // sortable: data.sortable || false,
377
+ useTabs: data.useTabs === true,
378
+ tabsLabel: `${data.tabsLabel || "label"}`,
379
+ addItem: data.addItem !== false,
380
+ insertItem: data.insertItem !== false,
381
+ cloneItem: data.cloneItem !== false,
382
+ moveItem: data.moveItem !== false,
383
+ removeItem: data.removeItem !== false,
384
+ clearItems: data.clearItems !== false
385
+ }, parent, options);
386
+ const result = fields(array);
387
+ const handleItems = (items) => {
388
+ if (Array.isArray(items)) {
389
+ array.fieldArray = {
390
+ wrappers: ["form-group"],
391
+ fieldGroup: items,
392
+ };
393
+ return array;
505
394
  }
506
- this.next(options);
507
- });
395
+ const props = items.props || {};
396
+ if (props.type === "text" || props.type === "number") {
397
+ array.type = "chips";
398
+ array.wrappers = ["form-field"];
399
+ array.props = {
400
+ ...props,
401
+ ...array.props,
402
+ multiple: true
403
+ };
404
+ return array;
405
+ }
406
+ array.fieldArray = {
407
+ ...items,
408
+ props: {
409
+ ...items.props,
410
+ label: ""
411
+ }
412
+ };
413
+ return array;
414
+ };
415
+ return result instanceof Promise
416
+ ? result.then(handleItems)
417
+ : handleItems(result);
508
418
  }
419
+ async fixSelectOptions(field, options) {
420
+ if (!options)
421
+ return [];
422
+ for (const option of options) {
423
+ const classes = Array.isArray(option.classes) ? option.classes : [`${option.classes}`];
424
+ option.className = classes.filter(isStringWithVal).join(" ");
425
+ option.label = await this.language.getTranslation(option.label);
426
+ option.value = option.value ?? option.id;
427
+ option.id = option.id ?? option.value;
428
+ }
429
+ const control = field.formControl;
430
+ if (field.props.multiple || options.length === 0 || options.findIndex(o => o.value === control.value) >= 0)
431
+ return options;
432
+ control.setValue(options[0].value);
433
+ return options;
434
+ }
435
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormBuilderService, deps: [{ token: i0.Injector }, { token: API_SERVICE }, { token: LANGUAGE_SERVICE }], target: i0.ɵɵFactoryTarget.Injectable });
436
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormBuilderService });
509
437
  }
438
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormBuilderService, decorators: [{
439
+ type: Injectable
440
+ }], ctorParameters: () => [{ type: i0.Injector }, { type: undefined, decorators: [{
441
+ type: Inject,
442
+ args: [API_SERVICE]
443
+ }] }, { type: undefined, decorators: [{
444
+ type: Inject,
445
+ args: [LANGUAGE_SERVICE]
446
+ }] }] });
510
447
 
511
448
  function getFormValidationErrors(controls, parentPath = "") {
512
449
  const errors = [];
513
450
  Object.entries(controls).forEach(([name, control], ix) => {
514
451
  const path = !parentPath ? name : `${parentPath}.${name}`;
515
- if (control instanceof FormGroup) {
452
+ if (control instanceof FormGroup$1) {
516
453
  getFormValidationErrors(control.controls, path).forEach(error => errors.push(error));
517
454
  return;
518
455
  }
519
- if (control instanceof FormArray) {
456
+ if (control instanceof FormArray$1) {
520
457
  control.controls.forEach((control, ix) => {
521
458
  getFormValidationErrors(control.controls, `${path}.${ix}`).forEach(error => errors.push(error));
522
459
  });
@@ -529,9 +466,10 @@ function getFormValidationErrors(controls, parentPath = "") {
529
466
  return errors;
530
467
  }
531
468
 
532
- class DynamicFormService extends DynamicFormService$1 {
469
+ class DynamicFormService {
533
470
  openApi;
534
471
  injector;
472
+ builder;
535
473
  get api() {
536
474
  return this.openApi.api;
537
475
  }
@@ -539,183 +477,72 @@ class DynamicFormService extends DynamicFormService$1 {
539
477
  return this.api.language;
540
478
  }
541
479
  schemas;
542
- constructor(cs, vs, openApi, injector) {
543
- super(cs, vs);
480
+ constructor(openApi, injector, builder) {
544
481
  this.openApi = openApi;
545
482
  this.injector = injector;
483
+ this.builder = builder;
484
+ }
485
+ async getFormFieldsForSchema(name, customizeOrOptions) {
486
+ const group = await this.getFormFieldGroupForSchema(name, customizeOrOptions);
487
+ return group.fieldGroup;
546
488
  }
547
- async serializeForm(form, validate) {
548
- if (!form.group)
489
+ async serializeForm(form, validate = true) {
490
+ const fields = form.config();
491
+ if (!fields)
549
492
  return null;
550
493
  if (validate) {
551
494
  await this.validateForm(form);
552
495
  }
553
- return this.serialize(form.model, form.group);
554
- }
555
- async getFormModelForSchema(name, customizeOrOptions) {
556
- return (await this.getFormGroupModelForSchema(name, customizeOrOptions)).group;
557
- }
558
- getErrors(form) {
559
- this.showErrors(form);
560
- return new Promise(resolve => {
561
- setTimeout(() => {
562
- resolve(getFormValidationErrors(form.group.controls, ""));
563
- }, 500);
564
- });
565
- }
566
- createFormGroup(formModel, options, parent) {
567
- const group = super.createFormGroup(formModel, options, parent);
568
- if (!parent) {
569
- group.valueChanges.pipe(debounceTime(500)).subscribe(() => {
570
- this.notifyChanges(formModel, group, formModel);
571
- });
572
- }
573
- return group;
496
+ return this.serialize(fields);
574
497
  }
575
- patchGroup(value, formModel, formGroup) {
576
- value = ObjectUtils.copy(value);
577
- this.patchValues(value, formModel, formGroup);
578
- formGroup.patchValue(value);
579
- this.detectChanges();
580
- }
581
- patchForm(value, component) {
582
- value = ObjectUtils.copy(value);
583
- this.patchValues(value, component.model, component.group);
584
- component.group.patchValue(value);
585
- this.detectChanges(component);
586
- }
587
- validateForm(form, showErrors = true) {
588
- if (!form.group)
498
+ async validateForm(form, showErrors = true) {
499
+ const group = form.group();
500
+ if (!group)
589
501
  return Promise.resolve();
590
502
  return new Promise((resolve, reject) => {
591
- form.group.statusChanges.pipe(first(status => status == "VALID" || status == "INVALID")).subscribe(status => {
503
+ group.statusChanges
504
+ .pipe(first(status => status == "VALID" || status == "INVALID"))
505
+ .subscribe(status => {
592
506
  if (showErrors) {
593
- this.showErrors(form);
507
+ this.showErrorsForGroup(group);
594
508
  }
595
509
  if (status == "VALID") {
596
510
  resolve(null);
597
511
  return;
598
512
  }
599
- console.log(`Form errors:`, getFormValidationErrors(form.group.controls));
600
- reject(null);
513
+ reject(getFormValidationErrors(group.controls));
601
514
  });
602
- form.group.updateValueAndValidity();
515
+ group.updateValueAndValidity();
603
516
  });
604
517
  }
605
- async serialize(formModel, formGroup) {
518
+ async serialize(fields) {
606
519
  const result = {};
607
- if (!formModel || !formGroup || !formGroup.value)
520
+ if (!fields)
608
521
  return result;
609
- for (const i in formModel) {
610
- const subModel = formModel[i];
611
- const subControl = this.findControlByModel(subModel, formGroup);
612
- const serializer = subModel.additional?.serializer;
522
+ for (const field of fields) {
523
+ const serializer = field.serializer;
524
+ const key = `${field.key}`;
525
+ const props = field.props || {};
613
526
  if (ObjectUtils.isFunction(serializer)) {
614
- result[subModel.id] = await serializer(subModel, subControl);
615
- continue;
616
- }
617
- if (subModel.hidden && !subModel.additional?.serialize)
618
- continue;
619
- if (subModel instanceof DynamicFormArrayModel) {
620
- const length = Array.isArray(subControl.value) ? subControl.value.length : 0;
621
- const subArray = subControl;
622
- const resArray = [];
623
- for (let i = 0; i < length; i++) {
624
- const itemModel = subModel.get(i);
625
- resArray.push(await this.serialize(itemModel.group, subArray.at(i)));
626
- }
627
- result[subModel.id] = resArray;
628
- continue;
629
- }
630
- if (subModel instanceof DynamicInputModel && !ObjectUtils.isNullOrUndefined(subControl.value)) {
631
- result[subModel.id] = subModel.inputType == "number"
632
- ? parseFloat((`${subControl.value}` || "0").replace(/,/gi, ".")) ?? null
633
- : subControl.value;
527
+ result[key] = await serializer(field, this.injector);
634
528
  continue;
635
529
  }
636
- if (subModel instanceof DynamicFormGroupModel) {
637
- result[subModel.id] = await this.serialize(subModel.group, subControl);
530
+ if (field.hide && !field.serialize) {
638
531
  continue;
639
532
  }
640
- result[subModel.id] = subControl.value;
641
- }
642
- return result;
643
- }
644
- showErrors(form) {
645
- this.showErrorsForGroup(form.group);
646
- this.detectChanges(form);
647
- }
648
- notifyChanges(formModel, formGroup, root) {
649
- if (!formModel || !formGroup)
650
- return;
651
- for (const i in formModel) {
652
- const subModel = formModel[i];
653
- const subControl = this.findControlByModel(subModel, formGroup);
654
- if (subModel instanceof DynamicFormArrayModel) {
655
- const length = Array.isArray(subControl.value) ? subControl.value.length : 0;
656
- const subArray = subControl;
657
- for (let i = 0; i < length; i++) {
658
- const itemModel = subModel.get(i);
659
- this.notifyChanges(itemModel.group, subArray.at(i), root);
533
+ const control = field.formControl;
534
+ if (field.fieldGroup) {
535
+ const group = await this.serialize(field.fieldGroup);
536
+ if (field.key) {
537
+ result[key] = !field.fieldArray ? group : Object.values(group);
538
+ continue;
660
539
  }
540
+ Object.assign(result, group);
661
541
  continue;
662
542
  }
663
- if (subModel instanceof DynamicFormGroupModel) {
664
- this.notifyChanges(subModel.group, subControl, root);
665
- continue;
666
- }
667
- this.updateSelectOptions(subModel, subControl, root);
668
- }
669
- }
670
- patchValues(value, formModel, formGroup) {
671
- if (!value)
672
- return;
673
- formModel?.forEach(subModel => {
674
- const key = subModel.id;
675
- const subValue = value[key];
676
- const subControl = this.findControlByModel(subModel, formGroup);
677
- if ((subModel instanceof DynamicSelectModel || subModel instanceof DynamicRadioGroupModel) && ObjectUtils.isObject(subValue)) {
678
- value[key] = subValue.id || subValue._id || subValue;
679
- return;
680
- }
681
- if (subModel instanceof DynamicDatePickerModel) {
682
- value[key] = this.convertToDate(subValue);
683
- return;
684
- }
685
- if (subModel instanceof DynamicFormArrayModel) {
686
- const length = Array.isArray(subValue) ? subValue.length : 0;
687
- const subArray = subControl;
688
- while (subModel.size > length) {
689
- this.removeFormArrayGroup(0, subArray, subModel);
690
- }
691
- while (subModel.size < length) {
692
- this.insertFormArrayGroup(subModel.size, subArray, subModel);
693
- }
694
- for (let i = 0; i < length; i++) {
695
- const itemModel = subModel.get(i);
696
- this.patchValues(subValue[i], itemModel.group, subArray.at(i));
697
- }
698
- return;
699
- }
700
- if (subModel instanceof DynamicFormGroupModel) {
701
- this.patchValues(subValue, subModel.group, subControl);
702
- }
703
- });
704
- }
705
- updateSelectOptions(formControlModel, formControl, root) {
706
- if (formControlModel instanceof DynamicSelectModel) {
707
- let options = formControlModel.options$;
708
- if (options instanceof FormSubject) {
709
- options.notify(formControlModel, formControl, root);
710
- return;
711
- }
712
- while (options instanceof Subject && options.source) {
713
- options = options.source;
714
- if (options instanceof FormSubject) {
715
- options.notify(formControlModel, formControl, root);
716
- }
717
- }
543
+ result[key] = control.value;
718
544
  }
545
+ return result;
719
546
  }
720
547
  showErrorsForGroup(formGroup) {
721
548
  if (!formGroup)
@@ -726,12 +553,12 @@ class DynamicFormService extends DynamicFormService$1 {
726
553
  }
727
554
  showErrorsForControls(controls) {
728
555
  controls.forEach(control => {
729
- if (control instanceof FormGroup) {
556
+ if (control instanceof FormGroup$1) {
730
557
  this.showErrorsForGroup(control);
731
558
  return;
732
559
  }
733
560
  control.markAsTouched({ onlySelf: true });
734
- if (control instanceof FormArray) {
561
+ if (control instanceof FormArray$1) {
735
562
  this.showErrorsForControls(control.controls);
736
563
  }
737
564
  });
@@ -744,326 +571,287 @@ class DynamicFormService extends DynamicFormService$1 {
744
571
  : new Date(value);
745
572
  return isNaN(date) ? new Date() : date;
746
573
  }
747
- async getFormGroupModelForSchema(name, customizeOrOptions) {
748
- this.api.cache = {};
574
+ async getFormFieldGroupForSchema(name, customizeOrOptions) {
749
575
  this.schemas = await this.openApi.getSchemas();
750
- const fieldSets = [];
751
576
  const schemaOptions = ObjectUtils.isObject(customizeOrOptions) ? customizeOrOptions : {};
752
- const customizeModel = ObjectUtils.isFunction(customizeOrOptions) ? customizeOrOptions : schemaOptions.customizer;
577
+ const customizeConfig = ObjectUtils.isFunction(customizeOrOptions) ? customizeOrOptions : schemaOptions.customizer;
753
578
  const schema = this.schemas[name];
754
579
  const wrapOptions = {
755
580
  ...schemaOptions,
756
581
  schema,
757
- customizer: async (property, options, modelType, config, path) => {
758
- const pathPrefix = !path ? `` : `${path}.`;
759
- config.label = !config.label || !options.labelPrefix
760
- ? config.label || ""
761
- : await this.language.getTranslation(`${options.labelPrefix}.${pathPrefix}${config.label}`);
762
- const model = new modelType(config);
763
- if (model instanceof DynamicFormValueControlModel) {
764
- model.value = (model instanceof DynamicDatePickerModel)
765
- ? this.convertToDate(property.default) : property.default;
766
- }
767
- const modelPath = `${pathPrefix}${model.id}`;
768
- const layout = modelPath.toLowerCase().replace(/\./g, "-");
769
- model.layout = {
770
- grid: {
771
- host: `${layout} control-${model.id}`,
772
- container: `${layout}-container`
773
- }
774
- };
775
- if (!ObjectUtils.isFunction(customizeModel))
776
- return [model];
777
- let res = customizeModel(property, schema, model, config, modelPath, this.injector);
582
+ injector: this.injector,
583
+ customizer: async (property, options, config, parent) => {
584
+ config.defaultValue = `${config.type}`.startsWith("date")
585
+ ? this.convertToDate(property.default) : property.default;
586
+ if (!ObjectUtils.isFunction(customizeConfig))
587
+ return [config];
588
+ let res = customizeConfig(property, schema, config, parent, options, this.injector);
778
589
  if (!res)
779
- return [model];
590
+ return [config];
780
591
  if (res instanceof Promise) {
781
592
  res = await res;
782
593
  }
783
594
  return Array.isArray(res) ? res : [res];
784
595
  }
785
596
  };
786
- const controls = await this.getFormModelForSchemaDef(schema, fieldSets, wrapOptions, "");
787
- const group = [...controls];
597
+ const config = {
598
+ key: FORM_ROOT_KEY,
599
+ wrappers: ["form-group"]
600
+ };
601
+ const fields = await this.getFormFieldsForSchemaDef(schema, config, wrapOptions);
602
+ const fieldGroup = [...fields];
788
603
  // Add id fields if necessary
789
- if (controls.length > 0) {
604
+ if (fields.length > 0) {
790
605
  const idFields = [
791
- createFormInput("id", { hidden: true }),
792
- createFormInput("_id", { hidden: true })
793
- ].filter(t => !controls.some(c => c.id == t.id));
794
- group.unshift(...idFields);
606
+ { key: "id", props: { hidden: true } },
607
+ { key: "_id", props: { hidden: true } },
608
+ ];
609
+ fieldGroup.unshift(...idFields
610
+ .filter(t => !fields.some(c => c.key == t.key)));
795
611
  }
796
- const config = {
797
- id: "root",
798
- group,
799
- fieldSets
800
- };
612
+ config.fieldGroup = fieldGroup;
801
613
  const root = await wrapOptions.customizer({
802
- id: "root",
614
+ id: FORM_ROOT_KEY,
803
615
  type: "object",
804
616
  properties: schema?.properties || {}
805
- }, wrapOptions, DynamicFormGroupModel, config, "");
617
+ }, wrapOptions, config, null);
806
618
  // Check if the customized root wrapper returned an array
807
- controls.length = 0;
619
+ fields.length = 0;
808
620
  for (const model of root) {
809
- if (model instanceof DynamicFormGroupModel && model.id === "root") {
621
+ if (model.key === FORM_ROOT_KEY) {
810
622
  return model;
811
623
  }
812
624
  else {
813
- controls.push(model);
625
+ fields.push(model);
814
626
  }
815
627
  }
816
- return new DynamicFormGroupModel({
628
+ return {
817
629
  ...config,
818
- group: controls
819
- });
630
+ fieldGroup: fields
631
+ };
820
632
  }
821
- async getFormModelForSchemaDef(schema, fieldSets, options, path) {
633
+ async getFormFieldsForSchemaDef(schema, parent, options) {
822
634
  if (!schema)
823
635
  return [];
824
636
  const keys = Object.keys(schema.properties || {});
825
- const controls = [];
826
- for (const p of keys) {
827
- const property = schema.properties[p];
828
- const fsName = property.hidden ? null : String(property.fieldSet || "");
829
- if (fsName) {
830
- const fs = fieldSets.find(t => t.id === fsName);
831
- if (fs) {
832
- fs.fields.push(p);
833
- }
834
- else {
835
- fieldSets.push({ id: fsName, legend: `legend.${fsName}`, fields: [p] });
836
- }
837
- }
838
- const models = await this.getFormControlModels(property, options, path);
839
- controls.push(...models);
637
+ const fields = [];
638
+ // Collect all properties of this schema def
639
+ for (const key of keys) {
640
+ const property = schema.properties[key];
641
+ const propFields = await this.getFormFieldsForProp(property, options, parent);
642
+ fields.push(...propFields);
840
643
  }
841
- return controls.filter(t => null !== t);
644
+ return this.builder.createFieldSets(fields.filter(f => null !== f), parent, options);
842
645
  }
843
- checkIsEditorProperty(property) {
844
- if (!property.format)
845
- return false;
846
- return EDITOR_FORMATS.indexOf(property.format) >= 0 || property.format.endsWith("script");
646
+ async getFormFieldsForProp(property, options, parent) {
647
+ const field = await this.getFormFieldForProp(property, options, parent);
648
+ return !field ? [] : options.customizer(property, options, field, parent);
847
649
  }
848
- async getFormControlModels(property, options, path) {
650
+ async getFormFieldForProp(property, options, parent) {
849
651
  const $enum = property.items?.enum || property.enum;
850
652
  if (Array.isArray($enum) || isStringWithVal(property.optionsPath) || isStringWithVal(property.endpoint)) {
851
653
  if (property.format == "radio") {
852
- return options.customizer(property, options, DynamicRadioGroupModel, this.getFormRadioConfig(property, options), path);
654
+ return this.getFormRadioConfig(property, options, parent);
853
655
  }
854
- return options.customizer(property, options, DynamicSelectModel, this.getFormSelectConfig(property, options), path);
656
+ return this.getFormSelectConfig(property, options, parent);
855
657
  }
856
658
  switch (property.type) {
857
659
  case "string":
858
660
  case "number":
859
661
  case "integer":
860
662
  case "textarea":
861
- if (this.checkIsEditorProperty(property)) {
862
- return options.customizer(property, options, DynamicEditorModel, this.getFormEditorConfig(property, options), path);
863
- }
663
+ // if (this.checkIsEditorProperty(property)) {
664
+ // return this.getFormEditorConfig(property, options, parent);
665
+ // }
864
666
  if (property.format == "textarea") {
865
- return options.customizer(property, options, DynamicTextAreaModel, this.getFormTextareaConfig(property, options), path);
667
+ return this.getFormTextareaConfig(property, options, parent);
866
668
  }
867
669
  if (property.format == "date" || property.format == "date-time") {
868
- return options.customizer(property, options, DynamicDatePickerModel, this.getFormDatepickerConfig(property, options), path);
670
+ return this.getFormDatepickerConfig(property, options, parent);
869
671
  }
870
- return options.customizer(property, options, DynamicInputModel, this.getFormInputConfig(property, options), path);
871
- case "object":
872
- return options.customizer(property, options, DynamicEditorModel, this.getFormEditorConfig(property, options), path);
672
+ return this.getFormInputConfig(property, options, parent);
673
+ // case "object":
674
+ // return this.getFormEditorConfig(property, options, parent);
873
675
  case "boolean":
874
- return options.customizer(property, options, DynamicCheckboxModel, this.getFormCheckboxConfig(property, options), path);
676
+ return this.getFormCheckboxConfig(property, options, parent);
875
677
  case "array":
876
- if (findRefs(property).length > 0) {
877
- return options.customizer(property, options, DynamicFormArrayModel, await this.getFormArrayConfig(property, options, path), path);
878
- }
879
- else {
880
- return options.customizer(property, options, DynamicInputModel, this.getFormInputConfig(property, options), path);
881
- }
678
+ return this.getFormArrayConfig(property, options, parent);
882
679
  case "file":
883
- return options.customizer(property, options, DynamicFileUploadModel, this.getFormUploadConfig(property, options), path);
680
+ case "upload":
681
+ return this.getFormUploadConfig(property, options, parent);
884
682
  }
885
683
  if (findRefs(property).length > 0) {
886
- return options.customizer(property, options, DynamicFormGroupModel, await this.getFormGroupConfig(property, options, !path ? property.id : `${path}.${property.id}`), path);
684
+ return this.getFormGroupConfig(property, options, parent);
887
685
  }
888
- return [];
686
+ return null;
889
687
  }
890
- findModelByPath(parent, path) {
891
- if (path.length == 0)
892
- return parent;
893
- const next = path.shift();
894
- if (Array.isArray(parent)) {
895
- return this.findModelByPath(parent.find(t => t.id == next), path);
896
- }
897
- if (parent instanceof DynamicFormGroupModel || parent instanceof DynamicFormArrayGroupModel) {
898
- return this.findModelByPath(parent.group.find(t => t.id == next), path);
899
- }
900
- if (parent instanceof DynamicFormArrayModel) {
901
- return this.findModelByPath(parent.groups.find(t => t.index == next), path);
688
+ getFormFieldData(property, options) {
689
+ const validators = {};
690
+ const schema = options.schema;
691
+ if (ObjectUtils.isArray(schema.required) && schema.required.indexOf(property.id) >= 0) {
692
+ validators.required = requiredValidation();
902
693
  }
903
- return parent;
904
- }
905
- getFormControlConfig(property, options) {
906
- const validators = this.getValidators(property, options);
907
- const errorMessages = Object.keys(validators).reduce((res, key) => {
908
- res[key] = options.labelPrefix
909
- ? this.language.getTranslationSync(`${options.labelPrefix}.error.${key}`) : `error.${key}`;
910
- return res;
911
- }, {});
694
+ this.addPropertyValidators(validators, property);
695
+ this.addItemsValidators(validators, property.items);
912
696
  return {
913
- id: property.id,
914
- label: ObjectUtils.isString(property.label) ? property.label : property.id,
915
- hidden: property.hidden,
916
- disabled: property.disabled,
917
- validators,
918
- errorMessages,
919
- additional: Object.assign({
920
- // For material components
921
- appearance: "fill"
922
- }, property)
697
+ hidden: property.hidden === true,
698
+ fieldSet: property.fieldSet,
699
+ validators
923
700
  };
924
701
  }
925
- async getFormArrayConfig(property, options, path) {
926
- const fieldSets = [];
927
- const subSchemas = findRefs(property).map(ref => this.schemas[ref]);
928
- const subModels = await Promise.all(subSchemas.map(s => this.getFormModelForSchemaDef(s, fieldSets, options, path)));
929
- return Object.assign(this.getFormControlConfig(property, options), {
930
- groupFactory: () => mergeFormModels(ObjectUtils.copy(subModels)),
931
- initialCount: property.initialCount || 0,
932
- sortable: property.sortable || false,
933
- useTabs: property.useTabs || false,
934
- addItem: property.addItem !== false,
935
- insertItem: property.insertItem !== false,
936
- cloneItem: property.cloneItem !== false,
937
- moveItem: property.moveItem !== false,
938
- removeItem: property.removeItem !== false,
939
- clearItems: property.clearItems !== false
940
- });
941
- }
942
- async getFormGroupConfig(property, options, path) {
943
- const fieldSets = [];
702
+ async getFormArrayConfig(property, options, parent) {
703
+ return this.builder.createFormArray(property.id, async (sp) => {
704
+ const subSchemas = findRefs(property).map(ref => this.schemas[ref]);
705
+ if (subSchemas.length > 0) {
706
+ const subModels = await Promise.all(subSchemas.map(s => this.getFormFieldsForSchemaDef(s, sp, options)));
707
+ return mergeFormFields(ObjectUtils.copy(subModels));
708
+ }
709
+ return this.getFormFieldForProp(property.items, options, null);
710
+ }, {
711
+ ...this.getFormFieldData(property, options),
712
+ // initialCount: property.initialCount || 0,
713
+ // sortable: property.sortable || false,
714
+ useTabs: property.useTabs,
715
+ tabsLabel: property.tabsLabel,
716
+ addItem: property.addItem,
717
+ insertItem: property.insertItem,
718
+ cloneItem: property.cloneItem,
719
+ moveItem: property.moveItem,
720
+ removeItem: property.removeItem,
721
+ clearItems: property.clearItems
722
+ }, parent, options);
723
+ }
724
+ async getFormGroupConfig(property, options, parent) {
944
725
  const subSchemas = findRefs(property).map(ref => this.schemas[ref]);
945
- const subModels = await Promise.all(subSchemas.map(s => this.getFormModelForSchemaDef(s, fieldSets, options, path)));
946
- return Object.assign(this.getFormControlConfig(property, options), {
947
- fieldSets,
948
- group: mergeFormModels(subModels)
949
- });
950
- }
951
- getFormInputConfig(property, options) {
952
- let inputType = StringUtils.has(property.id, "password", "Password") ? "password" : (property.format || property.items?.type || property.type);
953
- switch (inputType) {
726
+ return this.builder.createFormGroup(property.id, async (sp) => {
727
+ const subModels = await Promise.all(subSchemas.map(s => this.getFormFieldsForSchemaDef(s, sp, options)));
728
+ return mergeFormFields(subModels);
729
+ }, {
730
+ ...this.getFormFieldData(property, options),
731
+ }, parent, options);
732
+ }
733
+ getFormInputConfig(property, options, parent) {
734
+ let type = StringUtils.has(property.id || "", "password", "Password") ? "password" : (property.format || property.type);
735
+ switch (type) {
954
736
  case "string":
955
- inputType = "text";
737
+ type = "text";
956
738
  break;
957
739
  case "boolean":
958
- inputType = "checkbox";
740
+ type = "checkbox";
959
741
  break;
960
742
  case "textarea":
961
- inputType = "textarea";
743
+ type = "textarea";
962
744
  break;
963
745
  case "integer":
964
- inputType = "number";
746
+ type = "number";
965
747
  break;
966
748
  }
967
749
  const sub = property.type == "array" ? property.items || property : property;
968
- return Object.assign(this.getFormControlConfig(property, options), {
969
- inputType,
970
- autoComplete: property.autoComplete || "off",
971
- multiple: property.type == "array",
972
- accept: ObjectUtils.isString(property.accept) ? property.accept : null,
973
- mask: ObjectUtils.isString(property.mask) ? property.mask : null,
974
- pattern: ObjectUtils.isString(property.pattern) ? property.pattern : null,
975
- step: isNaN(sub.step) ? (isNaN(property.step) ? 1 : property.step) : sub.step,
976
- min: isNaN(sub.minimum) ? MIN_INPUT_NUM : sub.minimum,
977
- max: isNaN(sub.maximum) ? MAX_INPUT_NUM : sub.maximum,
978
- minLength: isNaN(sub.minLength) ? 0 : sub.minLength,
979
- maxLength: isNaN(sub.maxLength) ? MAX_INPUT_NUM : sub.maxLength,
980
- placeholder: property.placeholder || ""
981
- });
982
- }
983
- getFormEditorConfig(property, options) {
984
- const sub = property.type == "array" ? property.items || property : property;
985
- return Object.assign(this.getFormControlConfig(property, options), {
986
- inputType: property.format || "json",
987
- convertObject: property.type !== "string",
988
- autoComplete: property.autoComplete || "off",
989
- multiple: property.type == "array",
990
- accept: ObjectUtils.isString(property.accept) ? property.accept : null,
991
- mask: ObjectUtils.isString(property.mask) ? property.mask : null,
992
- pattern: ObjectUtils.isString(property.pattern) ? property.pattern : null,
993
- step: isNaN(sub.step) ? (isNaN(property.step) ? 1 : property.step) : sub.step,
994
- minLength: isNaN(sub.minLength) ? 0 : sub.minLength,
995
- maxLength: isNaN(sub.maxLength) ? MAX_INPUT_NUM : sub.maxLength,
996
- placeholder: property.placeholder || ""
997
- });
998
- }
999
- getFormTextareaConfig(property, options) {
1000
- return Object.assign(this.getFormControlConfig(property, options), {
750
+ return this.builder.createFormInput(property.id, {
751
+ ...this.getFormFieldData(property, options),
752
+ type,
753
+ autocomplete: property.autocomplete,
754
+ pattern: property.pattern,
755
+ step: isNaN(sub.step) ? property.step : sub.step,
756
+ min: sub.minimum,
757
+ max: sub.maximum,
758
+ minLength: sub.minLength,
759
+ maxLength: sub.maxLength,
760
+ placeholder: property.placeholder
761
+ }, parent, options);
762
+ }
763
+ getFormTextareaConfig(property, options, parent) {
764
+ return this.builder.createFormInput(property.id, {
765
+ ...this.getFormFieldData(property, options),
766
+ type: "textarea",
767
+ autocomplete: property.autoComplete,
1001
768
  cols: property.cols || null,
1002
769
  rows: property.rows || 10,
1003
- wrap: property.wrap || false,
1004
- autoComplete: property.autoComplete || "off",
1005
- multiple: property.type == "array",
1006
- minLength: isNaN(property.minLength) ? 0 : property.minLength,
1007
- maxLength: isNaN(property.maxLength) ? MAX_INPUT_NUM : property.maxLength,
770
+ minLength: property.minLength,
771
+ maxLength: property.maxLength,
1008
772
  placeholder: property.placeholder || ""
1009
- });
1010
- }
1011
- getFormDatepickerConfig(property, options) {
1012
- return Object.assign(this.getFormControlConfig(property, options), {
1013
- format: property.dateFormat || "dd.MM.yyyy",
773
+ }, parent, options);
774
+ }
775
+ // getFormEditorConfig(property: IOpenApiSchemaProperty, options: ConfigForSchemaWrapOptions): DynamicEditorModelConfig {
776
+ // const sub = property.type == "array" ? property.items || property : property;
777
+ // return Object.assign(
778
+ // this.getFormControlConfig(property, options),
779
+ // {
780
+ // inputType: property.format || "json",
781
+ // convertObject: property.type !== "string",
782
+ // autoComplete: property.autoComplete || "off",
783
+ // multiple: property.type == "array",
784
+ // accept: ObjectUtils.isString(property.accept) ? property.accept : null,
785
+ // mask: ObjectUtils.isString(property.mask) ? property.mask : null,
786
+ // pattern: ObjectUtils.isString(property.pattern) ? property.pattern : null,
787
+ // step: isNaN(sub.step) ? (isNaN(property.step) ? 1 : property.step) : sub.step,
788
+ // minLength: isNaN(sub.minLength) ? 0 : sub.minLength,
789
+ // maxLength: isNaN(sub.maxLength) ? MAX_INPUT_NUM : sub.maxLength,
790
+ // placeholder: property.placeholder || ""
791
+ // }
792
+ // );
793
+ // }
794
+ getFormDatepickerConfig(property, options, parent) {
795
+ return this.builder.createFormInput(property.id, {
796
+ ...this.getFormFieldData(property, options),
797
+ type: property.format == "date-time" ? "datetime-local" : "date",
798
+ // format: property.dateFormat || "dd.MM.yyyy",
1014
799
  min: this.convertToDate(property.min),
1015
800
  max: this.convertToDate(property.max),
1016
- });
801
+ }, parent, options);
1017
802
  }
1018
- getFormSelectOptions(property, options) {
803
+ getFormRadioConfig(property, options, parent) {
804
+ return this.builder.createFormSelect(property.id, {
805
+ ...this.getFormFieldData(property, options),
806
+ options: field => this.getFormSelectOptions(property, options, field),
807
+ type: "radio",
808
+ multiple: property.type == "array",
809
+ groupBy: property.groupBy,
810
+ inline: property.inline,
811
+ allowEmpty: property.allowEmpty
812
+ }, parent, options);
813
+ }
814
+ getFormSelectConfig(property, options, parent) {
815
+ return this.builder.createFormSelect(property.id, {
816
+ ...this.getFormFieldData(property, options),
817
+ options: field => this.getFormSelectOptions(property, options, field),
818
+ type: "select",
819
+ multiple: property.type == "array",
820
+ groupBy: property.groupBy,
821
+ inline: property.inline,
822
+ allowEmpty: property.allowEmpty
823
+ }, parent, options);
824
+ }
825
+ getFormUploadConfig(property, options, parent) {
826
+ return this.builder.createFormUpload(property.id, {
827
+ ...this.getFormFieldData(property, options),
828
+ multiple: property.type === "array",
829
+ inline: property.inline,
830
+ accept: property.accept,
831
+ url: property.url,
832
+ maxSize: property.maxSize,
833
+ uploadOptions: property.uploadOptions
834
+ }, parent, options);
835
+ }
836
+ getFormCheckboxConfig(property, options, parent) {
837
+ return this.builder.createFormInput(property.id, {
838
+ ...this.getFormFieldData(property, options),
839
+ type: "checkbox",
840
+ indeterminate: property.indeterminate || false
841
+ }, parent, options);
842
+ }
843
+ getFormSelectOptions(property, options, field) {
1019
844
  const $enum = property.items?.enum || property.enum;
1020
845
  if (Array.isArray($enum)) {
1021
- return new FormSelectSubject((selectModel, formControl) => {
1022
- const selectOptions = $enum.map(value => {
1023
- const label = options.labelPrefix
1024
- ? this.language.getTranslationSync(`${options.labelPrefix}.${property.id}.${value}`)
1025
- : `${property.id}.${value}`;
1026
- return { value, label };
1027
- });
1028
- return this.fixSelectOptions(selectModel, formControl, selectOptions);
1029
- });
1030
- }
1031
- if (isStringWithVal(property.optionsPath)) {
1032
- return new FormSelectSubject(async (selectModel, control, root, indexes) => {
1033
- let path = property.optionsPath;
1034
- let target = control;
1035
- let model = selectModel;
1036
- if (path.startsWith("$root")) {
1037
- path = path.substring(5);
1038
- while (target.parent) {
1039
- target = target.parent;
1040
- }
1041
- model = root;
1042
- }
1043
- while (path.startsWith(".")) {
1044
- path = path.substring(1);
1045
- if (target.parent) {
1046
- target = target.parent;
1047
- }
1048
- model = model.parent || root;
1049
- }
1050
- Object.keys(indexes).forEach(key => {
1051
- path = path.replace(key, indexes[key]);
1052
- });
1053
- model = this.findModelByPath(model, path.split("."));
1054
- const modelOptions = model instanceof DynamicSelectModel
1055
- ? await firstValueFrom(model.options$) :
1056
- [];
1057
- const value = ObjectUtils.getValue(target.value, path);
1058
- const options = (!ObjectUtils.isArray(value) ? [] : value).map(value => {
1059
- const modelOption = modelOptions.find(t => t.value == value);
1060
- return { value, label: modelOption?.label || value };
1061
- });
1062
- return this.fixSelectOptions(selectModel, control, options);
1063
- });
1064
- }
1065
- return new FormSelectSubject(async (selectModel, control) => {
1066
- const entries = Object.entries(control.root?.controls || {});
846
+ return from(this.builder.fixSelectOptions(field, $enum.map(value => {
847
+ const label = options.labelPrefix
848
+ ? this.language.getTranslationSync(`${options.labelPrefix}.${property.id}.${value}`)
849
+ : `${property.id}.${value}`;
850
+ return { value, label };
851
+ })));
852
+ }
853
+ if (isStringWithVal(property.endpoint)) {
854
+ const entries = Object.entries(field.formControl.root?.controls || {});
1067
855
  const endpoint = entries.reduce((res, [key, control]) => {
1068
856
  return this.replaceOptionsEndpoint(res, key, control?.value);
1069
857
  }, `${property.endpoint}`);
@@ -1080,46 +868,37 @@ class DynamicFormService extends DynamicFormService$1 {
1080
868
  };
1081
869
  });
1082
870
  });
1083
- const options = (await this.api.cache[endpoint]).map(t => Object.assign({}, t));
1084
- return this.fixSelectOptions(selectModel, control, options);
1085
- });
1086
- }
1087
- getFormRadioConfig(property, options) {
1088
- return Object.assign(this.getFormControlConfig(property, options), {
1089
- options: this.getFormSelectOptions(property, options),
1090
- });
1091
- }
1092
- getFormSelectConfig(property, options) {
1093
- return Object.assign(this.getFormControlConfig(property, options), {
1094
- options: this.getFormSelectOptions(property, options),
1095
- multiple: property.type == "array",
1096
- groupBy: property.groupBy,
1097
- inline: property.inline,
1098
- allowEmpty: property.allowEmpty,
1099
- });
1100
- }
1101
- getFormUploadConfig(property, options) {
1102
- const url = this.api.url(property.url || "assets");
1103
- const { accept, autoUpload, maxSize, minSize, removeUrl, showFileList } = property;
1104
- return Object.assign(this.getFormControlConfig(property, options), {
1105
- url,
1106
- accept,
1107
- autoUpload,
1108
- maxSize,
1109
- minSize,
1110
- removeUrl,
1111
- showFileList
1112
- });
1113
- }
1114
- getFormCheckboxConfig(property, options) {
1115
- return Object.assign(this.getFormControlConfig(property, options), {
1116
- indeterminate: property.indeterminate || false
1117
- });
1118
- }
1119
- cloneFormArrayGroup(index, formArray, formArrayModel) {
1120
- this.insertFormArrayGroup(index, formArray, formArrayModel);
1121
- this.patchGroup(formArray.at(index + 1).value, formArrayModel.groups[index].group, formArray.at(index));
1122
- formArrayModel.filterGroups();
871
+ const options = this.api.cache[endpoint];
872
+ return from(options.then(opts => {
873
+ return this.builder.fixSelectOptions(field, opts.map(o => Object.assign({}, o)));
874
+ }));
875
+ }
876
+ let path = property.optionsPath;
877
+ let control = field.formControl;
878
+ let current = field;
879
+ if (path.startsWith("$root")) {
880
+ path = path.substring(5);
881
+ control = control.root || control;
882
+ while (current.parent) {
883
+ current = current.parent;
884
+ }
885
+ }
886
+ while (path.startsWith(".")) {
887
+ path = path.substring(1);
888
+ control = control.parent || control;
889
+ current = current.parent || current;
890
+ }
891
+ control = !path ? control : control.get(path);
892
+ return control.valueChanges.pipe(startWith(control.value), distinctUntilChanged(), switchMap(async (controlVal) => {
893
+ const currentOpts = current.props.options;
894
+ const finalOpts = isObservable(currentOpts)
895
+ ? await firstValueFrom(currentOpts)
896
+ : (Array.isArray(currentOpts) ? currentOpts : []);
897
+ return this.builder.fixSelectOptions(field, (!Array.isArray(controlVal) ? [] : controlVal).map(value => {
898
+ const modelOption = finalOpts.find(t => t.value == value);
899
+ return { value, label: modelOption?.label || value };
900
+ }));
901
+ }));
1123
902
  }
1124
903
  replaceOptionsEndpoint(endpoint, key, value) {
1125
904
  if (ObjectUtils.isObject(value)) {
@@ -1134,46 +913,27 @@ class DynamicFormService extends DynamicFormService$1 {
1134
913
  }
1135
914
  return endpoint.replace(new RegExp(`\\$${key}`, "gi"), `${value ?? ""}`);
1136
915
  }
1137
- async fixSelectOptions(model, control, options) {
1138
- if (!options)
1139
- return [];
1140
- for (const option of options) {
1141
- option.classes = [option.classes, model.getClasses(option, model, control, this.injector)].filter(isStringWithVal).join(" ");
1142
- option.label = await this.language.getTranslation(option.label);
1143
- }
1144
- return options;
1145
- }
1146
- getValidators(property, options) {
1147
- const validators = {};
1148
- const schema = options.schema;
1149
- if (ObjectUtils.isArray(schema.required) && schema.required.indexOf(property.id) >= 0) {
1150
- validators.required = null;
1151
- }
1152
- this.addPropertyValidators(validators, property);
1153
- this.addItemsValidators(validators, property.items);
1154
- return validators;
1155
- }
1156
916
  addPropertyValidators(validators, property) {
1157
917
  if (!property)
1158
918
  return;
1159
919
  if (!isNaN(property.minLength)) {
1160
- validators.minLength = property.minLength;
920
+ validators.minLength = minLengthValidation(property.minLength);
1161
921
  }
1162
922
  if (!isNaN(property.maxLength)) {
1163
- validators.maxLength = property.maxLength;
923
+ validators.maxLength = maxLengthValidation(property.maxLength);
1164
924
  }
1165
925
  if (!isNaN(property.minimum)) {
1166
- validators.min = property.minimum;
926
+ validators.min = minValueValidation(property.minimum);
1167
927
  }
1168
928
  if (!isNaN(property.maximum)) {
1169
- validators.max = property.maximum;
1170
- }
1171
- if (isString(property.pattern) && property.pattern.length) {
1172
- validators.pattern = property.pattern;
929
+ validators.max = maxValueValidation(property.maximum);
1173
930
  }
931
+ // if (isString(property.pattern) && property.pattern.length) {
932
+ // validators.pattern = property.pattern;
933
+ // }
1174
934
  switch (property.format) {
1175
935
  case "email":
1176
- validators.email = null;
936
+ validators.email = emailValidation();
1177
937
  break;
1178
938
  }
1179
939
  }
@@ -1181,123 +941,89 @@ class DynamicFormService extends DynamicFormService$1 {
1181
941
  if (!items)
1182
942
  return;
1183
943
  if (!isNaN(items.minLength)) {
1184
- validators.itemsMinLength = items.minLength;
944
+ validators.itemsMinLength = minLengthValidation(items.minLength, true);
1185
945
  }
1186
946
  if (!isNaN(items.maxLength)) {
1187
- validators.itemsMaxLength = items.maxLength;
947
+ validators.itemsMaxLength = maxLengthValidation(items.maxLength, true);
1188
948
  }
1189
949
  if (!isNaN(items.minimum)) {
1190
- validators.itemsMinValue = items.minimum;
950
+ validators.itemsMinValue = minValueValidation(items.minimum, true);
1191
951
  }
1192
952
  if (!isNaN(items.maximum)) {
1193
- validators.itemsMaxValue = items.maximum;
953
+ validators.itemsMaxValue = maxValueValidation(items.maximum, true);
1194
954
  }
1195
955
  }
1196
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicFormService, deps: [{ token: i1.DynamicFormComponentService }, { token: i1.DynamicFormValidationService }, { token: OpenApiService }, { token: Injector }], target: i0.ɵɵFactoryTarget.Injectable });
1197
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicFormService });
956
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormService, deps: [{ token: i2.OpenApiService }, { token: i0.Injector }, { token: DynamicFormBuilderService }], target: i0.ɵɵFactoryTarget.Injectable });
957
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormService });
1198
958
  }
1199
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicFormService, decorators: [{
959
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormService, decorators: [{
1200
960
  type: Injectable
1201
- }], ctorParameters: () => [{ type: i1.DynamicFormComponentService }, { type: i1.DynamicFormValidationService }, { type: i2.OpenApiService, decorators: [{
1202
- type: Inject,
1203
- args: [OpenApiService]
1204
- }] }, { type: i0.Injector, decorators: [{
1205
- type: Inject,
1206
- args: [Injector]
1207
- }] }] });
961
+ }], ctorParameters: () => [{ type: i2.OpenApiService }, { type: i0.Injector }, { type: DynamicFormBuilderService }] });
1208
962
 
1209
963
  class AsyncSubmitDirective {
1210
- toaster;
1211
- cdr;
1212
- zone;
1213
- elem;
1214
- renderer;
1215
- method;
1216
- form;
1217
- context;
1218
- onSuccess;
1219
- onError;
1220
- loading;
1221
- disabled;
1222
- callback;
1223
- subscription;
964
+ method = input(null, { alias: "async-submit" });
965
+ form = input();
966
+ context = input();
967
+ onSuccess = output();
968
+ onError = output();
969
+ toaster = inject(TOASTER_SERVICE);
970
+ renderer = inject(Renderer2);
971
+ elem = inject(ElementRef);
972
+ status = computed(() => {
973
+ const form = this.form();
974
+ return form?.status() || null;
975
+ });
976
+ group = computed(() => {
977
+ const form = this.form();
978
+ return form?.group() || null;
979
+ });
980
+ loading = signal(false);
981
+ callback = signal(null);
1224
982
  get isDisabled() {
1225
- return this.disabled;
1226
- }
1227
- set isDisabled(value) {
1228
- this.disabled = value;
1229
- if (value) {
1230
- this.renderer.setAttribute(this.elem.nativeElement, "disabled", "disabled");
1231
- return;
1232
- }
1233
- this.renderer.removeAttribute(this.elem.nativeElement, "disabled");
983
+ return this.status() !== "VALID";
1234
984
  }
1235
985
  get isLoading() {
1236
- return this.loading;
1237
- }
1238
- constructor(toaster, cdr, zone, elem, renderer) {
1239
- this.toaster = toaster;
1240
- this.cdr = cdr;
1241
- this.zone = zone;
1242
- this.elem = elem;
1243
- this.renderer = renderer;
1244
- this.onSuccess = new EventEmitter();
1245
- this.onError = new EventEmitter();
1246
- if (elem.nativeElement.tagName !== "BUTTON")
1247
- return;
1248
- renderer.setAttribute(elem.nativeElement, "type", "button");
986
+ return this.loading();
1249
987
  }
1250
- ngOnChanges(changes) {
1251
- // Clear old subscription
1252
- this.subscription?.unsubscribe();
1253
- // Check if form changed
1254
- if (changes.form) {
1255
- const form = changes.form.currentValue;
1256
- if (!form)
1257
- return;
1258
- // Force form for checking changes after fields get autofilled by the browser
1259
- // setTimeout(() => {
1260
- // console.log(
1261
- // this.elem.nativeElement,
1262
- // this.elem.nativeElement.focus
1263
- // );
1264
- // this.elem.nativeElement.focus?.();
1265
- // }, 1500);
1266
- }
1267
- // Handle other things if we have a form instance
1268
- if (!this.form)
1269
- return;
1270
- this.isDisabled = this.form.group?.status !== "VALID";
1271
- this.cdr.detectChanges();
1272
- this.subscription = ObservableUtils.multiSubscription(this.form.group?.statusChanges.subscribe(() => {
1273
- const status = this.form.group?.status;
1274
- this.isDisabled = status !== "VALID";
1275
- this.cdr.detectChanges();
1276
- if (!this.callback || status == "PENDING")
988
+ constructor() {
989
+ effect(() => {
990
+ if (this.elem.nativeElement.tagName === "BUTTON") {
991
+ this.renderer.setAttribute(this.elem.nativeElement, "type", "button");
992
+ }
993
+ });
994
+ effect(() => {
995
+ const status = this.status();
996
+ const cb = this.callback();
997
+ if (!cb || status == "PENDING")
1277
998
  return;
1278
- if (!this.disabled) {
1279
- this.callback();
999
+ if (status === "VALID") {
1000
+ cb();
1280
1001
  }
1281
- this.callback = null;
1282
- }), this.form.onSubmit?.pipe(debounceTime(200)).subscribe(() => this.callMethod()));
1283
- }
1284
- ngOnDestroy() {
1285
- this.subscription?.unsubscribe();
1002
+ this.callback.set(null);
1003
+ });
1004
+ effect(() => {
1005
+ const form = this.form();
1006
+ if (!form)
1007
+ return;
1008
+ const sub = outputToObservable(form.onSubmit)
1009
+ .pipe(debounceTime(200)).subscribe(() => this.callMethod());
1010
+ return () => sub.unsubscribe();
1011
+ });
1286
1012
  }
1287
1013
  click() {
1288
- this.callback = () => this.callMethod();
1289
- const status = this.form.group?.status;
1290
- if (status !== "VALID" && status !== "INVALID")
1014
+ const status = this.status();
1015
+ if (status !== "VALID" && status !== "INVALID") {
1016
+ this.callback.set(() => this.callMethod());
1291
1017
  return;
1292
- this.callback();
1293
- this.callback = null;
1018
+ }
1019
+ this.callMethod();
1294
1020
  }
1295
1021
  callMethod() {
1296
- if (this.loading)
1022
+ if (this.loading())
1297
1023
  return;
1298
- this.loading = true;
1299
- this.method(this.form, this.context).then(result => {
1300
- this.loading = false;
1024
+ this.loading.set(true);
1025
+ this.method()(this.form(), this.context).then(result => {
1026
+ this.loading.set(false);
1301
1027
  if (result) {
1302
1028
  this.onSuccess.emit(result);
1303
1029
  this.toaster.success(result.message, result.context);
@@ -1305,36 +1031,22 @@ class AsyncSubmitDirective {
1305
1031
  }, reason => {
1306
1032
  if (!reason || !reason.message)
1307
1033
  throw new Error("Reason must implement IAsyncMessage interface");
1308
- this.loading = false;
1034
+ this.loading.set(false);
1309
1035
  this.onError.emit(reason);
1310
1036
  this.toaster.error(reason.message, reason.context);
1311
1037
  });
1312
1038
  }
1313
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AsyncSubmitDirective, deps: [{ token: TOASTER_SERVICE }, { token: i0.ChangeDetectorRef }, { token: i0.NgZone }, { token: i0.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
1314
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.0.3", type: AsyncSubmitDirective, isStandalone: false, selector: "[async-submit]", inputs: { method: ["async-submit", "method"], form: "form", context: "context" }, outputs: { onSuccess: "onSuccess", onError: "onError" }, host: { listeners: { "click": "click()" }, properties: { "class.disabled": "this.isDisabled", "class.loading": "this.isLoading" } }, exportAs: ["async-submit"], usesOnChanges: true, ngImport: i0 });
1039
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AsyncSubmitDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1040
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.14", type: AsyncSubmitDirective, isStandalone: false, selector: "[async-submit]", inputs: { method: { classPropertyName: "method", publicName: "async-submit", isSignal: true, isRequired: false, transformFunction: null }, form: { classPropertyName: "form", publicName: "form", isSignal: true, isRequired: false, transformFunction: null }, context: { classPropertyName: "context", publicName: "context", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSuccess: "onSuccess", onError: "onError" }, host: { listeners: { "click": "click()" }, properties: { "class.disabled": "this.isDisabled", "class.loading": "this.isLoading" } }, exportAs: ["async-submit"], ngImport: i0 });
1315
1041
  }
1316
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AsyncSubmitDirective, decorators: [{
1042
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: AsyncSubmitDirective, decorators: [{
1317
1043
  type: Directive,
1318
1044
  args: [{
1319
1045
  standalone: false,
1320
1046
  selector: "[async-submit]",
1321
1047
  exportAs: "async-submit"
1322
1048
  }]
1323
- }], ctorParameters: () => [{ type: undefined, decorators: [{
1324
- type: Inject,
1325
- args: [TOASTER_SERVICE]
1326
- }] }, { type: i0.ChangeDetectorRef }, { type: i0.NgZone }, { type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { method: [{
1327
- type: Input,
1328
- args: ["async-submit"]
1329
- }], form: [{
1330
- type: Input
1331
- }], context: [{
1332
- type: Input
1333
- }], onSuccess: [{
1334
- type: Output
1335
- }], onError: [{
1336
- type: Output
1337
- }], isDisabled: [{
1049
+ }], ctorParameters: () => [], propDecorators: { isDisabled: [{
1338
1050
  type: HostBinding,
1339
1051
  args: ["class.disabled"]
1340
1052
  }], isLoading: [{
@@ -1345,616 +1057,124 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
1345
1057
  args: ["click"]
1346
1058
  }] } });
1347
1059
 
1348
- class DynamicBaseFormComponent extends DynamicFormComponent {
1349
- formService;
1350
- events;
1351
- group = null;
1352
- model = null;
1353
- layout = null;
1354
- blur = new EventEmitter();
1355
- change = new EventEmitter();
1356
- focus = new EventEmitter();
1357
- groupModel;
1358
- labelPrefix;
1359
- getComponentType;
1360
- contentTemplates;
1361
- viewTemplates;
1362
- get status() {
1363
- return !this.group ? null : this.group.status;
1364
- }
1365
- onValueChange;
1366
- onStatusChange;
1367
- onSubmit;
1368
- onDetectChanges;
1369
- subscription = new Subscription();
1370
- groupSubscription = new Subscription();
1371
- constructor(formService, events, changeDetectorRef, componentService) {
1372
- super(changeDetectorRef, componentService);
1373
- this.formService = formService;
1374
- this.events = events;
1375
- this.groupModel = undefined;
1376
- this.labelPrefix = "";
1377
- this.getComponentType = () => null;
1378
- this.templates = new QueryList();
1379
- this.onValueChange = new EventEmitter();
1380
- this.onStatusChange = new EventEmitter();
1381
- this.onSubmit = new EventEmitter();
1382
- this.onDetectChanges = new EventEmitter();
1383
- }
1384
- submit() {
1385
- this.onSubmit.emit(this);
1386
- }
1387
- ngOnChanges(changes) {
1388
- this.groupSubscription.unsubscribe();
1389
- if (this.group) {
1390
- this.groupSubscription = ObservableUtils.multiSubscription(this.group.statusChanges.subscribe(() => {
1391
- this.onStatusChange.emit(this);
1392
- }), this.change.pipe(groupBy(ev => ev.model))
1393
- .pipe(mergeMap(t => t.pipe(debounceTime(500))))
1394
- .subscribe(ev => {
1395
- this.onValueChange.emit({ ...ev, form: this });
1396
- }));
1397
- }
1398
- if (changes.groupModel) {
1399
- this.model = this.groupModel?.group;
1400
- }
1401
- if (changes.model) {
1402
- this.groupModel = new DynamicFormGroupModel({ id: "root", group: this.model || [] });
1060
+ class DynamicFormComponent {
1061
+ builder = inject(DynamicFormBuilderService);
1062
+ labelPrefix = input("label");
1063
+ data = input({});
1064
+ fields = input(null);
1065
+ config$ = resource({
1066
+ request: () => ({
1067
+ fields: this.fields(),
1068
+ labelPrefix: this.labelPrefix()
1069
+ }),
1070
+ loader: async (p) => {
1071
+ const { fields, labelPrefix } = p.request;
1072
+ return fields || this.builder.resolveFormFields(this.data()?.constructor, null, {
1073
+ labelPrefix
1074
+ });
1403
1075
  }
1404
- }
1405
- ngAfterViewInit() {
1406
- this.subscription = ObservableUtils.multiSubscription(ObservableUtils.subscribe({
1407
- subjects: [this.contentTemplates.changes, this.viewTemplates.changes],
1408
- cb: () => {
1409
- const templates = this.contentTemplates.toArray().concat(this.viewTemplates.toArray());
1410
- this.templates.reset(templates);
1411
- }
1412
- }), this.events.languageChanged.subscribe(() => {
1413
- this.formService.notifyChanges(this.model, this.group, this.model);
1414
- this.formService.detectChanges(this);
1415
- }));
1416
- }
1417
- ngOnDestroy() {
1418
- super.ngOnDestroy();
1419
- this.subscription.unsubscribe();
1420
- this.groupSubscription.unsubscribe();
1421
- }
1422
- detectChanges() {
1423
- super.detectChanges();
1424
- this.onDetectChanges.emit(this);
1425
- }
1426
- insertFormArrayGroup(index, formArray, formArrayModel) {
1427
- this.formService.insertFormArrayGroup(index, formArray, formArrayModel);
1428
- this.detectChanges();
1429
- }
1430
- cloneFormArrayGroup(index, formArray, formArrayModel) {
1431
- this.formService.cloneFormArrayGroup(index, formArray, formArrayModel);
1432
- this.detectChanges();
1433
- }
1434
- removeFormArrayGroup(index, formArray, formArrayModel) {
1435
- this.formService.removeFormArrayGroup(index, formArray, formArrayModel);
1436
- this.detectChanges();
1437
- }
1438
- moveFormArrayGroup(index, step, formArray, formArrayModel) {
1439
- this.formService.moveFormArrayGroup(index, step, formArray, formArrayModel);
1440
- this.detectChanges();
1441
- }
1442
- clearFormArray(formArray, formArrayModel) {
1443
- this.formService.clearFormArray(formArray, formArrayModel);
1444
- this.detectChanges();
1445
- }
1446
- getClass(model) {
1447
- const parts = collectPathAble(model, p => p.id);
1448
- if (parts.length == 0)
1449
- return "";
1450
- if (model instanceof DynamicFormGroupModel) {
1451
- return `form-group-${parts.join("-")}`;
1076
+ });
1077
+ config = computed(() => this.config$.value());
1078
+ group = computed(() => {
1079
+ this.config();
1080
+ return new FormGroup$1({});
1081
+ });
1082
+ status$ = rxResource({
1083
+ request: () => this.group(),
1084
+ loader: p => p.request.statusChanges
1085
+ });
1086
+ status = computed(() => this.status$.value());
1087
+ onSubmit = output();
1088
+ options = {
1089
+ formState: {
1090
+ injector: inject(Injector)
1452
1091
  }
1453
- return `form-control-${parts.join("-")}`;
1092
+ };
1093
+ submit() {
1094
+ this.onSubmit.emit(this);
1454
1095
  }
1455
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormComponent, deps: [{ token: DynamicFormService }, { token: EventsService }, { token: i0.ChangeDetectorRef }, { token: i1.DynamicFormComponentService }], target: i0.ɵɵFactoryTarget.Component });
1456
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: DynamicBaseFormComponent, isStandalone: false, selector: "dynamic-base-form", inputs: { group: "group", model: "model", layout: "layout", groupModel: "groupModel", labelPrefix: "labelPrefix", getComponentType: "getComponentType" }, outputs: { blur: "blur", change: "change", focus: "focus", onValueChange: "onValueChange", onStatusChange: "onStatusChange", onSubmit: "onSubmit", onDetectChanges: "onDetectChanges" }, queries: [{ propertyName: "contentTemplates", predicate: DynamicTemplateDirective }], viewQueries: [{ propertyName: "viewTemplates", predicate: DynamicTemplateDirective, descendants: true }], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "", isInline: true, changeDetection: i0.ChangeDetectionStrategy.Default });
1096
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1097
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: DynamicFormComponent, isStandalone: false, selector: "dynamic-form", inputs: { labelPrefix: { classPropertyName: "labelPrefix", publicName: "labelPrefix", isSignal: true, isRequired: false, transformFunction: null }, data: { classPropertyName: "data", publicName: "data", isSignal: true, isRequired: false, transformFunction: null }, fields: { classPropertyName: "fields", publicName: "fields", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onSubmit: "onSubmit" }, ngImport: i0, template: "@if (config() && group()) {\n <form [formGroup]=\"group()\" (ngSubmit)=\"submit()\">\n <input type=\"submit\" [hidden]=\"true\" />\n <formly-form [model]=\"data()\"\n [fields]=\"config()\"\n [form]=\"group()\"\n [options]=\"options\"></formly-form>\n <ng-content></ng-content>\n </form>\n}\n", dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: i3.FormlyForm, selector: "formly-form", inputs: ["form", "model", "fields", "options"], outputs: ["modelChange"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1457
1098
  }
1458
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormComponent, decorators: [{
1099
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormComponent, decorators: [{
1459
1100
  type: Component,
1460
- args: [{
1461
- standalone: false,
1462
- selector: "dynamic-base-form",
1463
- template: "",
1464
- changeDetection: ChangeDetectionStrategy.Default
1465
- }]
1466
- }], ctorParameters: () => [{ type: DynamicFormService, decorators: [{
1467
- type: Inject,
1468
- args: [DynamicFormService]
1469
- }] }, { type: i2.EventsService, decorators: [{
1470
- type: Inject,
1471
- args: [EventsService]
1472
- }] }, { type: i0.ChangeDetectorRef }, { type: i1.DynamicFormComponentService }], propDecorators: { group: [{
1473
- type: Input
1474
- }], model: [{
1475
- type: Input
1476
- }], layout: [{
1477
- type: Input
1478
- }], blur: [{
1479
- type: Output
1480
- }], change: [{
1481
- type: Output
1482
- }], focus: [{
1483
- type: Output
1484
- }], groupModel: [{
1485
- type: Input
1486
- }], labelPrefix: [{
1487
- type: Input
1488
- }], getComponentType: [{
1489
- type: Input
1490
- }], contentTemplates: [{
1491
- type: ContentChildren,
1492
- args: [DynamicTemplateDirective]
1493
- }], viewTemplates: [{
1494
- type: ViewChildren,
1495
- args: [DynamicTemplateDirective]
1496
- }], onValueChange: [{
1497
- type: Output
1498
- }], onStatusChange: [{
1499
- type: Output
1500
- }], onSubmit: [{
1501
- type: Output
1502
- }], onDetectChanges: [{
1503
- type: Output
1504
- }] } });
1101
+ args: [{ standalone: false, selector: "dynamic-form", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "@if (config() && group()) {\n <form [formGroup]=\"group()\" (ngSubmit)=\"submit()\">\n <input type=\"submit\" [hidden]=\"true\" />\n <formly-form [model]=\"data()\"\n [fields]=\"config()\"\n [form]=\"group()\"\n [options]=\"options\"></formly-form>\n <ng-content></ng-content>\n </form>\n}\n" }]
1102
+ }] });
1505
1103
 
1506
- class DynamicBaseFormControlContainerComponent extends DynamicFormControlContainerComponent {
1507
- form;
1508
- cdr;
1509
- injector;
1510
- contentTemplateList = null;
1511
- klass = null;
1512
- context = null;
1513
- group = null;
1514
- hostClass = null;
1515
- inputTemplateList = null;
1516
- layout = null;
1517
- model = null;
1518
- blur = new EventEmitter();
1519
- change = new EventEmitter();
1520
- focus = new EventEmitter();
1521
- componentViewContainerRef = null;
1522
- get componentType() {
1523
- return this.form.getComponentType?.(this.model, this.injector)
1524
- ?? this.componentService.getCustomComponentType(this.model);
1525
- }
1526
- get startTemplate() {
1527
- return (this.model.type == DYNAMIC_FORM_CONTROL_TYPE_ARRAY)
1528
- ? this.layoutService.getAlignedTemplate(this.model, this.templates, "ARRAY_START")
1529
- : this.layoutService.getStartTemplate(this.model, this.templates);
1530
- }
1531
- get endTemplate() {
1532
- return (this.model.type == DYNAMIC_FORM_CONTROL_TYPE_ARRAY)
1533
- ? this.layoutService.getAlignedTemplate(this.model, this.templates, "ARRAY_END")
1534
- : this.layoutService.getEndTemplate(this.model, this.templates);
1535
- }
1536
- get formService() {
1537
- return this.form.formService;
1538
- }
1539
- onDetectChanges;
1540
- constructor(form, cdr, injector, cfr, layoutService, validationService, componentService, relationService) {
1541
- super(cdr, cfr, layoutService, validationService, componentService, relationService);
1542
- this.form = form;
1543
- this.cdr = cdr;
1544
- this.injector = injector;
1545
- }
1546
- ngOnInit() {
1547
- super.ngOnInit();
1548
- this.onDetectChanges = this.form.onDetectChanges.subscribe(() => {
1549
- this.changeDetectorRef.detectChanges();
1550
- });
1551
- }
1552
- ngOnDestroy() {
1553
- super.ngOnDestroy();
1554
- this.onDetectChanges.unsubscribe();
1555
- }
1556
- getLabel() {
1557
- if (this.form?.labelPrefix) {
1558
- const label = collectPathAble(this.model, p => p.id);
1559
- if (label.length == 0) {
1560
- return this.model.label;
1561
- }
1562
- label.unshift(this.form.labelPrefix);
1563
- return label.join(".");
1104
+ class DynamicFormArrayComponent extends FieldArrayType {
1105
+ currentTab = signal(0);
1106
+ clear() {
1107
+ const control = this.formControl;
1108
+ while (control.length > 0) {
1109
+ this.remove(0);
1564
1110
  }
1565
- return this.model.label;
1566
1111
  }
1567
- getLabelIcon() {
1568
- if (this.context instanceof DynamicFormArrayGroupModel) {
1569
- const arrayModel = this.context.context;
1570
- if (arrayModel && arrayModel.sortBy == this.model.id) {
1571
- return arrayModel.sortOrder;
1572
- }
1573
- }
1574
- return null;
1575
- }
1576
- clickLabel() {
1577
- if (this.context instanceof DynamicFormArrayGroupModel) {
1578
- const arrayModel = this.context.context;
1579
- if (arrayModel) {
1580
- arrayModel.sortBy = this.model.id;
1581
- }
1582
- }
1583
- }
1584
- createFormControlComponent() {
1585
- super.createFormControlComponent();
1586
- const component = this.componentRef?.instance;
1587
- if (!component || !ObjectUtils.isFunction(component.initialize))
1588
- return;
1589
- component.initialize(this.changeDetectorRef);
1590
- }
1591
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormControlContainerComponent, deps: [{ token: DynamicBaseFormComponent }, { token: i0.ChangeDetectorRef }, { token: i0.Injector }, { token: i0.ComponentFactoryResolver }, { token: i1.DynamicFormLayoutService }, { token: i1.DynamicFormValidationService }, { token: i1.DynamicFormComponentService }, { token: i1.DynamicFormRelationService }], target: i0.ɵɵFactoryTarget.Component });
1592
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: DynamicBaseFormControlContainerComponent, isStandalone: false, selector: "dynamic-base-form-control", inputs: { context: "context", group: "group", hostClass: "hostClass", inputTemplateList: ["templates", "inputTemplateList"], layout: "layout", model: "model" }, outputs: { blur: "blur", change: "change", focus: "focus" }, host: { properties: { "class": "this.klass" } }, providers: [
1593
- { provide: DynamicFormControlContainerComponent, useExisting: DynamicBaseFormControlContainerComponent }
1594
- ], queries: [{ propertyName: "contentTemplateList", predicate: DynamicTemplateDirective }], viewQueries: [{ propertyName: "componentViewContainerRef", first: true, predicate: ["componentViewContainer"], descendants: true, read: ViewContainerRef, static: true }], usesInheritance: true, ngImport: i0, template: "", isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1112
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormArrayComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1113
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.2.14", type: DynamicFormArrayComponent, isStandalone: false, selector: "dynamic-form-array", usesInheritance: true, ngImport: i0, template: "<div class=\"ngx-dynamic-form-array\">\n <label class=\"form-label\" *ngIf=\"props.label\">\n {{ props.label }}\n <p class=\"form-array-description\" *ngIf=\"props.description\">{{ props.description }}</p>\n </label>\n <div class=\"ngx-dynamic-form-container\">\n @if (props.useTabs) {\n <ul class=\"form-array-tabs\">\n @for (field of field.fieldGroup; track field.key; let ix = $index) {\n <li>\n <a class=\"btn\" [ngClass]=\"[currentTab() === ix ? 'btn-primary' : 'btn-secondary']\"\n (click)=\"currentTab.set(ix)\">\n {{ (field.formControl.value | getValue : props.tabsLabel) || ix + 1 }}\n </a>\n </li>\n }\n </ul>\n }\n @for (field of field.fieldGroup; track field.key; let ix = $index) {\n @if (!props.useTabs || ix === currentTab()) {\n <div class=\"form-array-item\">\n <div class=\"form-array-buttons\">\n @if (props.removeItem) {\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"remove(ix)\">\n <i icon=\"trash-outline\"></i>\n </button>\n }\n @if (props.insertItem) {\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"add(ix)\">\n <i icon=\"plus-outline\"></i>\n </button>\n }\n </div>\n <formly-field [field]=\"field\"></formly-field>\n </div>\n }\n }\n <div class=\"form-array-buttons\">\n @if (props.clearItems) {\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"clear()\">\n <i icon=\"trash-outline\"></i>\n {{ 'button.clear-items' | translate }}\n </button>\n }\n @if (props.addItem) {\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"add()\">\n <i icon=\"plus-outline\"></i>\n {{ 'button.insert-item' | translate }}\n </button>\n }\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.IconDirective, selector: "[icon]", inputs: ["icon", "activeIcon", "active"], outputs: ["activeChange"] }, { kind: "component", type: i3.FormlyField, selector: "formly-field", inputs: ["field"] }, { kind: "pipe", type: i2.GetValuePipe, name: "getValue" }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
1595
1114
  }
1596
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormControlContainerComponent, decorators: [{
1115
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormArrayComponent, decorators: [{
1597
1116
  type: Component,
1598
- args: [{
1599
- standalone: false,
1600
- selector: "dynamic-base-form-control",
1601
- template: "",
1602
- changeDetection: ChangeDetectionStrategy.OnPush,
1603
- providers: [
1604
- { provide: DynamicFormControlContainerComponent, useExisting: DynamicBaseFormControlContainerComponent }
1605
- ]
1606
- }]
1607
- }], ctorParameters: () => [{ type: DynamicBaseFormComponent }, { type: i0.ChangeDetectorRef }, { type: i0.Injector }, { type: i0.ComponentFactoryResolver }, { type: i1.DynamicFormLayoutService }, { type: i1.DynamicFormValidationService }, { type: i1.DynamicFormComponentService }, { type: i1.DynamicFormRelationService }], propDecorators: { contentTemplateList: [{
1608
- type: ContentChildren,
1609
- args: [DynamicTemplateDirective]
1610
- }], klass: [{
1611
- type: HostBinding,
1612
- args: ["class"]
1613
- }], context: [{
1614
- type: Input
1615
- }], group: [{
1616
- type: Input
1617
- }], hostClass: [{
1618
- type: Input
1619
- }], inputTemplateList: [{
1620
- type: Input,
1621
- args: ["templates"]
1622
- }], layout: [{
1623
- type: Input
1624
- }], model: [{
1625
- type: Input
1626
- }], blur: [{
1627
- type: Output
1628
- }], change: [{
1629
- type: Output
1630
- }], focus: [{
1631
- type: Output
1632
- }], componentViewContainerRef: [{
1633
- type: ViewChild,
1634
- args: ["componentViewContainer", {
1635
- read: ViewContainerRef,
1636
- static: true
1637
- }]
1638
- }] } });
1117
+ args: [{ standalone: false, selector: "dynamic-form-array", encapsulation: ViewEncapsulation.None, template: "<div class=\"ngx-dynamic-form-array\">\n <label class=\"form-label\" *ngIf=\"props.label\">\n {{ props.label }}\n <p class=\"form-array-description\" *ngIf=\"props.description\">{{ props.description }}</p>\n </label>\n <div class=\"ngx-dynamic-form-container\">\n @if (props.useTabs) {\n <ul class=\"form-array-tabs\">\n @for (field of field.fieldGroup; track field.key; let ix = $index) {\n <li>\n <a class=\"btn\" [ngClass]=\"[currentTab() === ix ? 'btn-primary' : 'btn-secondary']\"\n (click)=\"currentTab.set(ix)\">\n {{ (field.formControl.value | getValue : props.tabsLabel) || ix + 1 }}\n </a>\n </li>\n }\n </ul>\n }\n @for (field of field.fieldGroup; track field.key; let ix = $index) {\n @if (!props.useTabs || ix === currentTab()) {\n <div class=\"form-array-item\">\n <div class=\"form-array-buttons\">\n @if (props.removeItem) {\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"remove(ix)\">\n <i icon=\"trash-outline\"></i>\n </button>\n }\n @if (props.insertItem) {\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"add(ix)\">\n <i icon=\"plus-outline\"></i>\n </button>\n }\n </div>\n <formly-field [field]=\"field\"></formly-field>\n </div>\n }\n }\n <div class=\"form-array-buttons\">\n @if (props.clearItems) {\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"clear()\">\n <i icon=\"trash-outline\"></i>\n {{ 'button.clear-items' | translate }}\n </button>\n }\n @if (props.addItem) {\n <button type=\"button\" class=\"btn btn-sm btn-primary\" (click)=\"add()\">\n <i icon=\"plus-outline\"></i>\n {{ 'button.insert-item' | translate }}\n </button>\n }\n </div>\n </div>\n</div>\n" }]
1118
+ }] });
1639
1119
 
1640
- class DynamicBaseFormArrayComponent extends DynamicFormArrayComponent {
1641
- form;
1642
- injector;
1643
- cdr;
1644
- formLayout = null;
1645
- group = null;
1646
- layout = null;
1647
- model = null;
1648
- templates = null;
1649
- blur = new EventEmitter();
1650
- change = new EventEmitter();
1651
- customEvent = new EventEmitter();
1652
- focus = new EventEmitter();
1653
- components = null;
1654
- get useTabs() {
1655
- return this.model?.useTabs;
1656
- }
1657
- subscription;
1658
- constructor(layoutService, validationService, form, injector, cdr) {
1659
- super(layoutService, validationService);
1660
- this.form = form;
1661
- this.injector = injector;
1662
- this.cdr = cdr;
1663
- }
1664
- initialize(cdr) {
1665
- this.subscription = this.model.filteredGroups.subscribe(filteredGroups => {
1666
- this.updateGroups(filteredGroups);
1667
- });
1668
- this.model.initialize(this.array);
1669
- }
1670
- ngOnDestroy() {
1671
- if (this.subscription)
1672
- this.subscription.unsubscribe();
1673
- }
1674
- saveTab(index) {
1675
- this.model.saveTab(index, this.model.getFiltered(index), this.model, this.injector);
1676
- }
1677
- restoreTab() {
1678
- return this.model.restoreTab(this.model, this.injector);
1679
- }
1680
- getTabLabel(index, model) {
1681
- return this.model.getTabLabel(index, model, this.model, this.array, this.injector);
1682
- }
1683
- getClass(context, place, model) {
1684
- return [
1685
- context == "element" ? this.getModelClass(model) : null,
1686
- context == "element" ? this.getAdditionalClass(model) : null,
1687
- super.getClass(context, place, model),
1688
- model instanceof DynamicFormValueControlModel ? model.additional?.classes : null
1689
- ].filter(cls => !!cls).join(" ");
1690
- }
1691
- getModelClass(model) {
1692
- const parts = collectPathAble(model, p => p.id);
1693
- if (parts.length == 0)
1694
- return "";
1695
- if (model instanceof DynamicFormGroupModel$1) {
1696
- return `form-group-${parts.join("-")}`;
1697
- }
1698
- return `form-control-${parts.join("-")}`;
1699
- }
1700
- getAdditionalClass(model) {
1701
- if (model instanceof DynamicFormArrayModel) {
1702
- return model.additional?.classes;
1703
- }
1704
- if (model instanceof DynamicFormValueControlModel) {
1705
- return model.additional?.classes;
1706
- }
1707
- return null;
1708
- }
1709
- updateGroups(filteredGroups) {
1710
- this.cdr.detectChanges();
1711
- this.components.forEach(t => t.cdr.detectChanges());
1712
- }
1713
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormArrayComponent, deps: [{ token: i1.DynamicFormLayoutService }, { token: i1.DynamicFormValidationService }, { token: DynamicBaseFormComponent }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1714
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: DynamicBaseFormArrayComponent, isStandalone: false, selector: "dynamic-base-form-array", inputs: { formLayout: "formLayout", group: "group", layout: "layout", model: "model", templates: "templates" }, outputs: { blur: "blur", change: "change", customEvent: "customEvent", focus: "focus" }, viewQueries: [{ propertyName: "components", predicate: i0.forwardRef(() => DynamicBaseFormControlContainerComponent), descendants: true }], usesInheritance: true, ngImport: i0, template: "", isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1120
+ class DynamicFormChipsComponent extends FieldType {
1121
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormChipsComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1122
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DynamicFormChipsComponent, isStandalone: false, selector: "dynamic-form-chips", usesInheritance: true, ngImport: i0, template: "<chips [formControl]=\"formControl\"\n [type]=\"props.type\"\n [step]=\"props.step\"\n [minLength]=\"props.minLength\"\n [maxLength]=\"props.maxLength\"\n [min]=\"props.min\"\n [max]=\"props.max\"\n [multiple]=\"props.multiple\"\n [formlyAttributes]=\"field\">\n</chips>\n", dependencies: [{ kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i2.ChipsComponent, selector: "chips", inputs: ["value", "multiple", "disabled", "type", "min", "max", "minLength", "maxLength", "step", "placeholder", "unique", "options"], outputs: ["valueChange"] }, { kind: "directive", type: i3.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1715
1123
  }
1716
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormArrayComponent, decorators: [{
1124
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormChipsComponent, decorators: [{
1717
1125
  type: Component,
1718
- args: [{
1719
- standalone: false,
1720
- selector: "dynamic-base-form-array",
1721
- template: "",
1722
- changeDetection: ChangeDetectionStrategy.OnPush
1723
- }]
1724
- }], ctorParameters: () => [{ type: i1.DynamicFormLayoutService }, { type: i1.DynamicFormValidationService }, { type: DynamicBaseFormComponent }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }], propDecorators: { formLayout: [{
1725
- type: Input
1726
- }], group: [{
1727
- type: Input
1728
- }], layout: [{
1729
- type: Input
1730
- }], model: [{
1731
- type: Input
1732
- }], templates: [{
1733
- type: Input
1734
- }], blur: [{
1735
- type: Output
1736
- }], change: [{
1737
- type: Output
1738
- }], customEvent: [{
1739
- type: Output
1740
- }], focus: [{
1741
- type: Output
1742
- }], components: [{
1743
- type: ViewChildren,
1744
- args: [forwardRef(() => DynamicBaseFormControlContainerComponent)]
1745
- }] } });
1126
+ args: [{ standalone: false, selector: "dynamic-form-chips", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<chips [formControl]=\"formControl\"\n [type]=\"props.type\"\n [step]=\"props.step\"\n [minLength]=\"props.minLength\"\n [maxLength]=\"props.maxLength\"\n [min]=\"props.min\"\n [max]=\"props.max\"\n [multiple]=\"props.multiple\"\n [formlyAttributes]=\"field\">\n</chips>\n" }]
1127
+ }] });
1746
1128
 
1747
- class DynamicBaseFormControlComponent extends DynamicFormControlComponent {
1748
- form;
1749
- injector;
1750
- cdr;
1751
- formLayout = null;
1752
- group = null;
1753
- layout = null;
1754
- model = null;
1755
- blur = new EventEmitter();
1756
- change = new EventEmitter();
1757
- focus = new EventEmitter();
1758
- subscription;
1759
- constructor(layoutService, validationService, form, injector, cdr) {
1760
- super(layoutService, validationService);
1761
- this.form = form;
1762
- this.injector = injector;
1763
- this.cdr = cdr;
1764
- }
1765
- ngAfterViewInit() {
1766
- this.subscription = this.control.valueChanges.pipe(debounceTime(500)).subscribe(value => {
1767
- this.onValueChanged(value);
1768
- });
1769
- }
1770
- ngOnDestroy() {
1771
- if (!this.subscription)
1772
- return;
1773
- this.subscription.unsubscribe();
1774
- }
1775
- submit() {
1776
- this.form?.submit();
1777
- }
1778
- onValueChanged(value) {
1779
- }
1780
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormControlComponent, deps: [{ token: i1.DynamicFormLayoutService }, { token: i1.DynamicFormValidationService }, { token: DynamicBaseFormComponent, optional: true }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
1781
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: DynamicBaseFormControlComponent, isStandalone: false, selector: "dynamic-base-form-control", inputs: { formLayout: "formLayout", group: "group", layout: "layout", model: "model" }, outputs: { blur: "blur", change: "change", focus: "focus" }, usesInheritance: true, ngImport: i0, template: "", isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1129
+ class DynamicFormFieldComponent extends FieldWrapper {
1130
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormFieldComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1131
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DynamicFormFieldComponent, isStandalone: false, selector: "dynamic-form-field", usesInheritance: true, ngImport: i0, template: "<div [ngClass]=\"['ngx-dynamic-form-field', 'ngx-dynamic-form-' + field.type]\">\n <label class=\"control-label ng-star-inserted\" *ngIf=\"props.label\">\n {{ props.label | translate }}\n <span class=\"form-field-required\" *ngIf=\"props.required && props.hideRequiredMarker !== true\" aria-hidden=\"true\">*</span>\n <p class=\"form-field-description\" *ngIf=\"props.description\">\n {{ props.description | translate }}\n </p>\n </label>\n <div class=\"ngx-dynamic-form-control\">\n <ng-container #fieldComponent></ng-container>\n <div *ngIf=\"showError\" class=\"invalid-feedback\">\n <formly-validation-message\n id=\"{{ id }}-formly-validation-error\"\n [field]=\"field\"\n role=\"alert\"\n ></formly-validation-message>\n </div>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "component", type: i3.ɵFormlyValidationMessage, selector: "formly-validation-message", inputs: ["field"] }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }], encapsulation: i0.ViewEncapsulation.None });
1782
1132
  }
1783
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormControlComponent, decorators: [{
1133
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormFieldComponent, decorators: [{
1784
1134
  type: Component,
1785
- args: [{
1786
- standalone: false,
1787
- selector: "dynamic-base-form-control",
1788
- template: "",
1789
- changeDetection: ChangeDetectionStrategy.OnPush
1790
- }]
1791
- }], ctorParameters: () => [{ type: i1.DynamicFormLayoutService }, { type: i1.DynamicFormValidationService }, { type: DynamicBaseFormComponent, decorators: [{
1792
- type: Optional
1793
- }] }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }], propDecorators: { formLayout: [{
1794
- type: Input
1795
- }], group: [{
1796
- type: Input
1797
- }], layout: [{
1798
- type: Input
1799
- }], model: [{
1800
- type: Input
1801
- }], blur: [{
1802
- type: Output
1803
- }], change: [{
1804
- type: Output
1805
- }], focus: [{
1806
- type: Output
1807
- }] } });
1135
+ args: [{ standalone: false, selector: "dynamic-form-field", encapsulation: ViewEncapsulation.None, template: "<div [ngClass]=\"['ngx-dynamic-form-field', 'ngx-dynamic-form-' + field.type]\">\n <label class=\"control-label ng-star-inserted\" *ngIf=\"props.label\">\n {{ props.label | translate }}\n <span class=\"form-field-required\" *ngIf=\"props.required && props.hideRequiredMarker !== true\" aria-hidden=\"true\">*</span>\n <p class=\"form-field-description\" *ngIf=\"props.description\">\n {{ props.description | translate }}\n </p>\n </label>\n <div class=\"ngx-dynamic-form-control\">\n <ng-container #fieldComponent></ng-container>\n <div *ngIf=\"showError\" class=\"invalid-feedback\">\n <formly-validation-message\n id=\"{{ id }}-formly-validation-error\"\n [field]=\"field\"\n role=\"alert\"\n ></formly-validation-message>\n </div>\n </div>\n</div>\n" }]
1136
+ }] });
1808
1137
 
1809
- class DynamicBaseFormGroupComponent extends DynamicFormGroupComponent {
1810
- layoutService;
1811
- validationService;
1812
- formLayout = null;
1813
- group = null;
1814
- layout = null;
1815
- model = null;
1816
- templates = [];
1817
- blur = new EventEmitter();
1818
- change = new EventEmitter();
1819
- customEvent = new EventEmitter();
1820
- focus = new EventEmitter();
1821
- components = null;
1822
- constructor(layoutService, validationService) {
1823
- super(layoutService, validationService);
1824
- this.layoutService = layoutService;
1825
- this.validationService = validationService;
1826
- }
1827
- getClass(context, place, model) {
1828
- return [
1829
- context == "element" ? this.getModelClass(model) : null,
1830
- context == "element" ? this.getAdditionalClass(model) : null,
1831
- super.getClass(context, place, model)
1832
- ].filter(cls => !!cls).join(" ");
1833
- }
1834
- getModelClass(model) {
1835
- const parts = collectPathAble(model, p => p.id);
1836
- if (parts.length == 0)
1837
- return "";
1838
- if (model instanceof DynamicFormGroupModel) {
1839
- return `form-group-${parts.join("-")}`;
1840
- }
1841
- return `form-control-${parts.join("-")}`;
1842
- }
1843
- getAdditionalClass(model) {
1844
- if (model instanceof DynamicFormArrayModel) {
1845
- return model.additional?.classes;
1846
- }
1847
- if (model instanceof DynamicFormValueControlModel) {
1848
- return model.additional?.classes;
1849
- }
1850
- return null;
1138
+ class DynamicFormFieldsetComponent extends FieldWrapper {
1139
+ ngOnInit() {
1140
+ // console.log(this.field.id, this.field.props?.label, this.options);
1141
+ // console.log(this.field.parent);
1851
1142
  }
1852
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormGroupComponent, deps: [{ token: i1.DynamicFormLayoutService }, { token: i1.DynamicFormValidationService }], target: i0.ɵɵFactoryTarget.Component });
1853
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: DynamicBaseFormGroupComponent, isStandalone: false, selector: "dynamic-base-form-group", inputs: { formLayout: "formLayout", group: "group", layout: "layout", model: "model", templates: "templates" }, outputs: { blur: "blur", change: "change", customEvent: "customEvent", focus: "focus" }, viewQueries: [{ propertyName: "components", predicate: i0.forwardRef(() => DynamicFormControlContainerComponent), descendants: true }], usesInheritance: true, ngImport: i0, template: "", isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1143
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormFieldsetComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1144
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DynamicFormFieldsetComponent, isStandalone: false, selector: "dynamic-form-field", usesInheritance: true, ngImport: i0, template: "<div class=\"ngx-dynamic-form-fieldset\">\n <legend class=\"form-label\" *ngIf=\"props.label\">\n {{ props.label }}\n <p class=\"form-group-description\" *ngIf=\"props.description\">{{ props.description }}</p>\n </legend>\n <div class=\"ngx-dynamic-form-container\">\n <ng-container #fieldComponent></ng-container>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], encapsulation: i0.ViewEncapsulation.None });
1854
1145
  }
1855
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormGroupComponent, decorators: [{
1146
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormFieldsetComponent, decorators: [{
1856
1147
  type: Component,
1857
- args: [{
1858
- standalone: false,
1859
- selector: "dynamic-base-form-group",
1860
- template: "",
1861
- changeDetection: ChangeDetectionStrategy.OnPush
1862
- }]
1863
- }], ctorParameters: () => [{ type: i1.DynamicFormLayoutService }, { type: i1.DynamicFormValidationService }], propDecorators: { formLayout: [{
1864
- type: Input
1865
- }], group: [{
1866
- type: Input
1867
- }], layout: [{
1868
- type: Input
1869
- }], model: [{
1870
- type: Input
1871
- }], templates: [{
1872
- type: Input
1873
- }], blur: [{
1874
- type: Output
1875
- }], change: [{
1876
- type: Output
1877
- }], customEvent: [{
1878
- type: Output
1879
- }], focus: [{
1880
- type: Output
1881
- }], components: [{
1882
- type: ViewChildren,
1883
- args: [forwardRef(() => DynamicFormControlContainerComponent)]
1884
- }] } });
1148
+ args: [{ standalone: false, selector: "dynamic-form-field", encapsulation: ViewEncapsulation.None, template: "<div class=\"ngx-dynamic-form-fieldset\">\n <legend class=\"form-label\" *ngIf=\"props.label\">\n {{ props.label }}\n <p class=\"form-group-description\" *ngIf=\"props.description\">{{ props.description }}</p>\n </legend>\n <div class=\"ngx-dynamic-form-container\">\n <ng-container #fieldComponent></ng-container>\n </div>\n</div>\n" }]
1149
+ }] });
1885
1150
 
1886
- class DynamicBaseSelectComponent extends DynamicBaseFormControlComponent {
1887
- groups$;
1888
- hasOptions;
1889
- ngOnInit() {
1890
- this.groups$ = new BehaviorSubject([]);
1891
- this.subscription = this.model.options$.subscribe(options => {
1892
- const groupBy = this.model.inline || !this.model.multiple ? this.model.groupBy : null;
1893
- const grouped = options.reduce((res, option) => {
1894
- const key = replaceSpecialChars(groupBy ? option.props[this.model.groupBy] || "default" : "default", "-");
1895
- res[key] = res[key] || [];
1896
- res[key].push(option);
1897
- return res;
1898
- }, {});
1899
- const groups = Object.keys(grouped).map(group => {
1900
- return {
1901
- group,
1902
- options: grouped[group]
1903
- };
1904
- });
1905
- this.hasOptions = groups.length > 0;
1906
- this.groups$.next(groups);
1907
- this.cdr.detectChanges();
1908
- });
1909
- }
1910
- ngOnDestroy() {
1911
- if (this.subscription)
1912
- this.subscription.unsubscribe();
1913
- }
1914
- isSelected(option) {
1915
- if (this.model.multiple) {
1916
- return this.control.value?.indexOf(option.value) >= 0;
1917
- }
1918
- return this.control.value == option.value;
1919
- }
1920
- selectToggle(option, state) {
1921
- if (this.model.multiple) {
1922
- const value = Array.from(this.control.value || []);
1923
- const index = value.indexOf(option.value);
1924
- if (index >= 0) {
1925
- value.splice(index, 1);
1926
- }
1927
- if (state) {
1928
- value.push(option.value);
1929
- }
1930
- this.control.setValue(value);
1931
- this.onChange(value);
1932
- return;
1933
- }
1934
- this.control.setValue(option.value);
1935
- this.onChange(option.value);
1936
- }
1937
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1938
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: DynamicBaseSelectComponent, isStandalone: false, selector: "dynamic-base-select", usesInheritance: true, ngImport: i0, template: "", isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
1151
+ class DynamicFormGroupComponent extends FieldWrapper {
1152
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormGroupComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1153
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DynamicFormGroupComponent, isStandalone: false, selector: "dynamic-form-group", usesInheritance: true, ngImport: i0, template: "<div class=\"ngx-dynamic-form-group\">\n <label class=\"form-group-label\" *ngIf=\"props.label\">\n {{ props.label }}\n <p class=\"form-group-description\" *ngIf=\"props.description\">{{ props.description }}</p>\n </label>\n <div class=\"ngx-dynamic-form-container\">\n <ng-container #fieldComponent></ng-container>\n </div>\n</div>\n", dependencies: [{ kind: "directive", type: i1$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }], encapsulation: i0.ViewEncapsulation.None });
1939
1154
  }
1940
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseSelectComponent, decorators: [{
1155
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormGroupComponent, decorators: [{
1941
1156
  type: Component,
1942
- args: [{
1943
- standalone: false,
1944
- selector: "dynamic-base-select",
1945
- template: "",
1946
- changeDetection: ChangeDetectionStrategy.OnPush
1947
- }]
1157
+ args: [{ standalone: false, selector: "dynamic-form-group", encapsulation: ViewEncapsulation.None, template: "<div class=\"ngx-dynamic-form-group\">\n <label class=\"form-group-label\" *ngIf=\"props.label\">\n {{ props.label }}\n <p class=\"form-group-description\" *ngIf=\"props.description\">{{ props.description }}</p>\n </label>\n <div class=\"ngx-dynamic-form-container\">\n <ng-container #fieldComponent></ng-container>\n </div>\n</div>\n" }]
1158
+ }] });
1159
+
1160
+ class DynamicFormUploadComponent extends FieldType {
1161
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormUploadComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
1162
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.14", type: DynamicFormUploadComponent, isStandalone: false, selector: "dynamic-form-upload", usesInheritance: true, ngImport: i0, template: "<upload [formControl]=\"formControl\"\n [multiple]=\"props.multiple\"\n [inline]=\"props.inline\"\n [accept]=\"props.accept\"\n [baseUrl]=\"props.url\"\n [makeUpload]=\"props.createUploadData\"\n [formlyAttributes]=\"field\">\n</upload>\n", dependencies: [{ kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "component", type: i2.UploadComponent, selector: "upload", inputs: ["value", "disabled", "inline", "accept", "baseUrl", "message", "multiple", "buttonText", "makeUpload", "preProcess"], outputs: ["onUploaded", "onRemove"] }, { kind: "directive", type: i3.ɵFormlyAttributes, selector: "[formlyAttributes]", inputs: ["formlyAttributes", "id"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.None });
1163
+ }
1164
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: DynamicFormUploadComponent, decorators: [{
1165
+ type: Component,
1166
+ args: [{ standalone: false, selector: "dynamic-form-upload", encapsulation: ViewEncapsulation.None, changeDetection: ChangeDetectionStrategy.OnPush, template: "<upload [formControl]=\"formControl\"\n [multiple]=\"props.multiple\"\n [inline]=\"props.inline\"\n [accept]=\"props.accept\"\n [baseUrl]=\"props.url\"\n [makeUpload]=\"props.createUploadData\"\n [formlyAttributes]=\"field\">\n</upload>\n" }]
1948
1167
  }] });
1949
1168
 
1950
1169
  // --- Components ---
1951
1170
  const components = [
1952
- DynamicBaseFormComponent,
1953
- DynamicBaseFormArrayComponent,
1954
- DynamicBaseFormControlComponent,
1955
- DynamicBaseFormControlContainerComponent,
1956
- DynamicBaseFormGroupComponent,
1957
- DynamicBaseSelectComponent
1171
+ DynamicFormComponent,
1172
+ DynamicFormArrayComponent,
1173
+ DynamicFormChipsComponent,
1174
+ DynamicFormFieldComponent,
1175
+ DynamicFormFieldsetComponent,
1176
+ DynamicFormGroupComponent,
1177
+ DynamicFormUploadComponent
1958
1178
  ];
1959
1179
  // --- Directives ---
1960
1180
  const directives = [
@@ -1962,23 +1182,30 @@ const directives = [
1962
1182
  ];
1963
1183
  // --- Pipes ---
1964
1184
  const pipes = [];
1965
- function defaultFormControlProvider() {
1966
- return () => null;
1967
- }
1968
1185
 
1969
1186
  class NgxDynamicFormModule {
1970
1187
  static getProviders(config) {
1188
+ const { providers } = FormlyModule.forRoot({
1189
+ types: [
1190
+ { name: "array", component: DynamicFormArrayComponent },
1191
+ { name: "chips", component: DynamicFormChipsComponent },
1192
+ { name: "upload", component: DynamicFormUploadComponent, wrappers: ["form-field"] },
1193
+ { name: "file", extends: "upload" },
1194
+ { name: "translation", extends: "array" },
1195
+ ],
1196
+ wrappers: [
1197
+ { name: "form-field", component: DynamicFormFieldComponent },
1198
+ { name: "form-fieldset", component: DynamicFormFieldsetComponent },
1199
+ { name: "form-group", component: DynamicFormGroupComponent },
1200
+ ],
1201
+ extras: {
1202
+ renderFormlyFieldElement: false
1203
+ }
1204
+ });
1971
1205
  return [
1206
+ ...providers,
1972
1207
  DynamicFormService,
1973
- {
1974
- provide: DynamicFormService$1,
1975
- useExisting: DynamicFormService
1976
- },
1977
- {
1978
- provide: DYNAMIC_FORM_CONTROL_MAP_FN,
1979
- useFactory: (config?.controlProvider || defaultFormControlProvider),
1980
- deps: [Injector]
1981
- }
1208
+ DynamicFormBuilderService
1982
1209
  ];
1983
1210
  }
1984
1211
  static forRoot(config) {
@@ -1990,41 +1217,27 @@ class NgxDynamicFormModule {
1990
1217
  static provideForms(config) {
1991
1218
  return makeEnvironmentProviders(NgxDynamicFormModule.getProviders(config));
1992
1219
  }
1993
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgxDynamicFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1994
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.3", ngImport: i0, type: NgxDynamicFormModule, declarations: [DynamicBaseFormComponent, DynamicBaseFormArrayComponent, DynamicBaseFormControlComponent, DynamicBaseFormControlContainerComponent, DynamicBaseFormGroupComponent, DynamicBaseSelectComponent, AsyncSubmitDirective], imports: [CommonModule,
1220
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxDynamicFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1221
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.2.14", ngImport: i0, type: NgxDynamicFormModule, declarations: [DynamicFormComponent, DynamicFormArrayComponent, DynamicFormChipsComponent, DynamicFormFieldComponent, DynamicFormFieldsetComponent, DynamicFormGroupComponent, DynamicFormUploadComponent, AsyncSubmitDirective], imports: [CommonModule,
1995
1222
  FormsModule,
1996
1223
  ReactiveFormsModule,
1997
- NgxUtilsModule], exports: [DynamicBaseFormComponent, DynamicBaseFormArrayComponent, DynamicBaseFormControlComponent, DynamicBaseFormControlContainerComponent, DynamicBaseFormGroupComponent, DynamicBaseSelectComponent, AsyncSubmitDirective, FormsModule,
1224
+ NgxUtilsModule,
1225
+ FormlyModule], exports: [DynamicFormComponent, DynamicFormArrayComponent, DynamicFormChipsComponent, DynamicFormFieldComponent, DynamicFormFieldsetComponent, DynamicFormGroupComponent, DynamicFormUploadComponent, AsyncSubmitDirective, FormsModule,
1998
1226
  ReactiveFormsModule,
1999
- NgxUtilsModule] });
2000
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgxDynamicFormModule, providers: [
2001
- ...pipes,
2002
- { provide: NG_VALIDATORS, useValue: validateJSON, multi: true },
2003
- { provide: NG_VALIDATORS, useValue: validateRequiredTranslation, multi: true },
2004
- { provide: NG_VALIDATORS, useValue: validateItemsMinLength, multi: true },
2005
- { provide: NG_VALIDATORS, useValue: validateItemsMaxLength, multi: true },
2006
- { provide: NG_VALIDATORS, useValue: validateItemsMinValue, multi: true },
2007
- { provide: NG_VALIDATORS, useValue: validateItemsMaxValue, multi: true },
2008
- {
2009
- provide: DYNAMIC_VALIDATORS,
2010
- useValue: new Map([
2011
- ["json", validateJSON],
2012
- ["requiredTranslation", validateRequiredTranslation],
2013
- ["phone", validatePhone],
2014
- ["itemsMinLength", validateItemsMinLength],
2015
- ["itemsMaxLength", validateItemsMaxLength],
2016
- ["itemsMinValue", validateItemsMinValue],
2017
- ["itemsMaxValue", validateItemsMaxValue],
2018
- ])
2019
- }
1227
+ NgxUtilsModule,
1228
+ FormlyModule] });
1229
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxDynamicFormModule, providers: [
1230
+ ...pipes
2020
1231
  ], imports: [CommonModule,
2021
1232
  FormsModule,
2022
1233
  ReactiveFormsModule,
2023
- NgxUtilsModule, FormsModule,
1234
+ NgxUtilsModule,
1235
+ FormlyModule, FormsModule,
2024
1236
  ReactiveFormsModule,
2025
- NgxUtilsModule] });
1237
+ NgxUtilsModule,
1238
+ FormlyModule] });
2026
1239
  }
2027
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgxDynamicFormModule, decorators: [{
1240
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.14", ngImport: i0, type: NgxDynamicFormModule, decorators: [{
2028
1241
  type: NgModule,
2029
1242
  args: [{
2030
1243
  declarations: [
@@ -2036,7 +1249,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
2036
1249
  CommonModule,
2037
1250
  FormsModule,
2038
1251
  ReactiveFormsModule,
2039
- NgxUtilsModule
1252
+ NgxUtilsModule,
1253
+ FormlyModule
2040
1254
  ],
2041
1255
  exports: [
2042
1256
  ...components,
@@ -2044,28 +1258,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
2044
1258
  ...pipes,
2045
1259
  FormsModule,
2046
1260
  ReactiveFormsModule,
2047
- NgxUtilsModule
1261
+ NgxUtilsModule,
1262
+ FormlyModule
2048
1263
  ],
2049
1264
  providers: [
2050
- ...pipes,
2051
- { provide: NG_VALIDATORS, useValue: validateJSON, multi: true },
2052
- { provide: NG_VALIDATORS, useValue: validateRequiredTranslation, multi: true },
2053
- { provide: NG_VALIDATORS, useValue: validateItemsMinLength, multi: true },
2054
- { provide: NG_VALIDATORS, useValue: validateItemsMaxLength, multi: true },
2055
- { provide: NG_VALIDATORS, useValue: validateItemsMinValue, multi: true },
2056
- { provide: NG_VALIDATORS, useValue: validateItemsMaxValue, multi: true },
2057
- {
2058
- provide: DYNAMIC_VALIDATORS,
2059
- useValue: new Map([
2060
- ["json", validateJSON],
2061
- ["requiredTranslation", validateRequiredTranslation],
2062
- ["phone", validatePhone],
2063
- ["itemsMinLength", validateItemsMinLength],
2064
- ["itemsMaxLength", validateItemsMaxLength],
2065
- ["itemsMinValue", validateItemsMinValue],
2066
- ["itemsMaxValue", validateItemsMaxValue],
2067
- ])
2068
- }
1265
+ ...pipes
2069
1266
  ]
2070
1267
  }]
2071
1268
  }] });
@@ -2074,5 +1271,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImpor
2074
1271
  * Generated bundle index. Do not edit.
2075
1272
  */
2076
1273
 
2077
- export { AsyncSubmitDirective, DynamicBaseFormArrayComponent, DynamicBaseFormComponent, DynamicBaseFormControlComponent, DynamicBaseFormControlContainerComponent, DynamicBaseFormGroupComponent, DynamicBaseSelectComponent, DynamicEditorModel, DynamicFormArrayGroupModel, DynamicFormArrayModel, DynamicFormGroupModel, DynamicFormOption, DynamicFormService, DynamicSelectModel, EDITOR_FORMATS, FormSelectSubject, FormSubject, MAX_INPUT_NUM, MIN_INPUT_NUM, NgxDynamicFormModule, collectPathAble, createFormArray, createFormCheckbox, createFormDate, createFormEditor, createFormFile, createFormGroup, createFormInput, createFormSelect, createFormTextarea, customizeFormModel, getDynamicPath, getFormComponent, mergeFormModels, replaceSpecialChars, validateItemsMaxLength, validateItemsMaxValue, validateItemsMinLength, validateItemsMinValue, validateJSON, validatePhone, validateRequiredTranslation };
1274
+ export { AsyncSubmitDirective, DynamicFormArrayComponent, DynamicFormBuilderService, DynamicFormChipsComponent, DynamicFormComponent, DynamicFormFieldComponent, DynamicFormFieldsetComponent, DynamicFormGroupComponent, DynamicFormService, DynamicFormUploadComponent, EDITOR_FORMATS, FORM_ROOT_KEY, FormFile, FormGroup, FormInput, FormModel, FormSelect, FormSerializable, FormUpload, MAX_INPUT_NUM, MIN_INPUT_NUM, NgxDynamicFormModule, customizeFormField, emailValidation, jsonValidation, maxLengthValidation, maxValueValidation, mergeFormFields, minLengthValidation, minValueValidation, phoneValidation, replaceSpecialChars, requiredValidation, translationValidation, validationMessage };
2078
1275
  //# sourceMappingURL=stemy-ngx-dynamic-form.mjs.map