@stemy/ngx-dynamic-form 13.3.12 → 19.0.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.
- package/fesm2022/stemy-ngx-dynamic-form.mjs +1993 -0
- package/fesm2022/stemy-ngx-dynamic-form.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/ngx-dynamic-form/common-types.d.ts +38 -38
- package/ngx-dynamic-form/components/base/dynamic-base-form-array.component.d.ts +38 -38
- package/ngx-dynamic-form/components/base/dynamic-base-form-control-container.component.d.ts +39 -39
- package/ngx-dynamic-form/components/base/dynamic-base-form-control.component.d.ts +26 -26
- package/ngx-dynamic-form/components/base/dynamic-base-form-group.component.d.ts +25 -25
- package/ngx-dynamic-form/components/base/dynamic-base-form.component.d.ts +48 -48
- package/ngx-dynamic-form/components/base/dynamic-base-select.component.d.ts +15 -16
- package/ngx-dynamic-form/directives/async-submit.directive.d.ts +30 -30
- package/ngx-dynamic-form/ngx-dynamic-form.imports.d.ts +12 -12
- package/ngx-dynamic-form/ngx-dynamic-form.module.d.ts +19 -19
- package/ngx-dynamic-form/services/dynamic-form.service.d.ts +58 -58
- package/ngx-dynamic-form/utils/creators.d.ts +17 -17
- package/ngx-dynamic-form/utils/customizer.d.ts +14 -14
- package/ngx-dynamic-form/utils/dynamic-editor.model.d.ts +11 -11
- package/ngx-dynamic-form/utils/dynamic-form-array.model.d.ts +69 -69
- package/ngx-dynamic-form/utils/dynamic-form-group.model.d.ts +14 -14
- package/ngx-dynamic-form/utils/dynamic-select.model.d.ts +39 -39
- package/ngx-dynamic-form/utils/form-select-subject.d.ts +6 -6
- package/ngx-dynamic-form/utils/form-subject.d.ts +10 -10
- package/ngx-dynamic-form/utils/misc.d.ts +11 -11
- package/ngx-dynamic-form/utils/validation-errors.d.ts +11 -11
- package/ngx-dynamic-form/utils/validators.d.ts +8 -8
- package/package.json +23 -32
- package/public_api.d.ts +21 -21
|
@@ -0,0 +1,1993 @@
|
|
|
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, DynamicFormValueControlModel, 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
|
+
import * as i2 from '@stemy/ngx-utils';
|
|
5
|
+
import { ObjectUtils, TimerUtils, cachedFactory, StringUtils, OpenApiService, TOASTER_SERVICE, ObservableUtils, EventsService, NgxUtilsModule } from '@stemy/ngx-utils';
|
|
6
|
+
import { __decorate } from 'tslib';
|
|
7
|
+
import { BehaviorSubject, of, isObservable, Subject, firstValueFrom, Subscription } from 'rxjs';
|
|
8
|
+
import { map, debounceTime, groupBy, mergeMap, first } from 'rxjs/operators';
|
|
9
|
+
import * as i0 from '@angular/core';
|
|
10
|
+
import { Injector, Injectable, Inject, EventEmitter, Directive, Input, Output, HostBinding, HostListener, Component, ChangeDetectionStrategy, ContentChildren, ViewChildren, ViewContainerRef, ViewChild, forwardRef, NgModule } from '@angular/core';
|
|
11
|
+
import { FormGroup, FormArray, FormsModule, ReactiveFormsModule, NG_VALIDATORS } from '@angular/forms';
|
|
12
|
+
import { CommonModule } from '@angular/common';
|
|
13
|
+
|
|
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
|
+
}
|
|
23
|
+
}
|
|
24
|
+
__decorate([
|
|
25
|
+
serializable()
|
|
26
|
+
], DynamicEditorModel.prototype, "type", void 0);
|
|
27
|
+
|
|
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
|
+
}
|
|
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;
|
|
97
|
+
}
|
|
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;
|
|
117
|
+
});
|
|
118
|
+
this.getTabLabel = ObjectUtils.isFunction(config.getTabLabel) ? config.getTabLabel : ((index) => {
|
|
119
|
+
return `${index + 1}`;
|
|
120
|
+
});
|
|
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
|
+
}
|
|
168
|
+
}
|
|
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
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
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
|
+
}
|
|
210
|
+
}
|
|
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.mOptions = this.mOptions || [];
|
|
225
|
+
}
|
|
226
|
+
updateOptions() {
|
|
227
|
+
this.options$ = of(this.mOptions);
|
|
228
|
+
}
|
|
229
|
+
set options(options) {
|
|
230
|
+
if (Array.isArray(options)) {
|
|
231
|
+
this.mOptions = options.map(optionConfig => new DynamicFormOption(optionConfig));
|
|
232
|
+
this.updateOptions();
|
|
233
|
+
}
|
|
234
|
+
else if (isObservable(options)) {
|
|
235
|
+
this.options$ = options.pipe(map(optionsConfig => {
|
|
236
|
+
this.mOptions = optionsConfig.map(optionConfig => new DynamicFormOption(optionConfig));
|
|
237
|
+
return this.mOptions;
|
|
238
|
+
}));
|
|
239
|
+
}
|
|
240
|
+
else {
|
|
241
|
+
this.updateOptions();
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
get options() {
|
|
245
|
+
return this.mOptions;
|
|
246
|
+
}
|
|
247
|
+
insert(index, optionConfig) {
|
|
248
|
+
const option = new DynamicFormOption(optionConfig);
|
|
249
|
+
this.mOptions.splice(index, 0, option);
|
|
250
|
+
this.updateOptions();
|
|
251
|
+
return option;
|
|
252
|
+
}
|
|
253
|
+
remove(...indices) {
|
|
254
|
+
indices.forEach(index => this.mOptions.splice(index, 1));
|
|
255
|
+
this.updateOptions();
|
|
256
|
+
}
|
|
257
|
+
}
|
|
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
|
+
return res;
|
|
266
|
+
}
|
|
267
|
+
function createFormCheckbox(id, config, layout) {
|
|
268
|
+
const res = createFormConfig(id, config);
|
|
269
|
+
res.indeterminate = config.indeterminate || false;
|
|
270
|
+
return new DynamicCheckboxModel(res, layout);
|
|
271
|
+
}
|
|
272
|
+
function createFormDate(id, config, layout) {
|
|
273
|
+
const res = createFormConfig(id, config);
|
|
274
|
+
res.autoFocus = config.autoFocus || false;
|
|
275
|
+
res.focusedDate = config.focusedDate || new Date();
|
|
276
|
+
res.inline = config.inline || false;
|
|
277
|
+
return new DynamicDatePickerModel(res, layout);
|
|
278
|
+
}
|
|
279
|
+
function createFormEditor(id, config, layout) {
|
|
280
|
+
const res = createFormConfig(id, config);
|
|
281
|
+
return new DynamicEditorModel(res, layout);
|
|
282
|
+
}
|
|
283
|
+
function createFormArray(id, config, layout) {
|
|
284
|
+
const res = createFormConfig(id, config);
|
|
285
|
+
return new DynamicFormArrayModel(res, layout);
|
|
286
|
+
}
|
|
287
|
+
function createFormGroup(id, config, layout) {
|
|
288
|
+
const res = createFormConfig(id, config);
|
|
289
|
+
res.name = config.name || "";
|
|
290
|
+
return new DynamicFormGroupModel(res, layout);
|
|
291
|
+
}
|
|
292
|
+
function createFormInput(id, config, type = "text", layout) {
|
|
293
|
+
const res = createFormConfig(id, config);
|
|
294
|
+
res.inputType = config.inputType || type;
|
|
295
|
+
res.placeholder = config.placeholder || (config.inputType == "mask" ? "_" : "");
|
|
296
|
+
res.step = config.step || 1;
|
|
297
|
+
res.mask = config.mask || null;
|
|
298
|
+
return new DynamicInputModel(res, layout);
|
|
299
|
+
}
|
|
300
|
+
function createFormSelect(id, config, layout) {
|
|
301
|
+
const res = createFormConfig(id, config);
|
|
302
|
+
res.options = config.options || [];
|
|
303
|
+
return new DynamicSelectModel(res, layout);
|
|
304
|
+
}
|
|
305
|
+
function createFormTextarea(id, config, layout) {
|
|
306
|
+
const res = createFormConfig(id, config);
|
|
307
|
+
res.cols = config.cols || 10;
|
|
308
|
+
res.rows = config.rows || 3;
|
|
309
|
+
res.wrap = config.wrap || "soft";
|
|
310
|
+
return new DynamicTextAreaModel(res, layout);
|
|
311
|
+
}
|
|
312
|
+
function createFormFile(id, config, layout) {
|
|
313
|
+
const res = createFormConfig(id, config);
|
|
314
|
+
res.accept = config.accept || ["jpg", "jpeg", "png"];
|
|
315
|
+
res.multiple = config.multiple || false;
|
|
316
|
+
res.url = ObjectUtils.isString(config.url) ? config.url : "assets";
|
|
317
|
+
return new DynamicFileUploadModel(res, layout);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function getFormComponent(...providers) {
|
|
321
|
+
const factory = cachedFactory(providers);
|
|
322
|
+
return (model, injector) => {
|
|
323
|
+
const customizers = factory(injector);
|
|
324
|
+
for (const customizer of customizers) {
|
|
325
|
+
const component = customizer.acceptModel(model) ? customizer.getFormComponent(model) : null;
|
|
326
|
+
if (component) {
|
|
327
|
+
return component;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
return null;
|
|
331
|
+
};
|
|
332
|
+
}
|
|
333
|
+
function customizeFormModel(...providers) {
|
|
334
|
+
const factory = cachedFactory(providers);
|
|
335
|
+
return async (property, schema, model, config, injector) => {
|
|
336
|
+
const customizers = factory(injector);
|
|
337
|
+
for (const customizer of customizers) {
|
|
338
|
+
const accept = customizer.acceptModel(model);
|
|
339
|
+
if (accept) {
|
|
340
|
+
return customizer.customizeModel(model, config, property, schema);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
return model;
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function isStringWithVal(val) {
|
|
348
|
+
return typeof val == "string" && val.length > 0;
|
|
349
|
+
}
|
|
350
|
+
function findRefs(property) {
|
|
351
|
+
const refs = Array.isArray(property.allOf)
|
|
352
|
+
? property.allOf.map(o => o.$ref).filter(isStringWithVal)
|
|
353
|
+
: [property.items?.$ref, property.$ref].filter(isStringWithVal);
|
|
354
|
+
return refs.map(t => t.split("/").pop());
|
|
355
|
+
}
|
|
356
|
+
function replaceSpecialChars(str, to = "-") {
|
|
357
|
+
return `${str}`.replace(/[&\/\\#, +()$~%.@'":*?<>{}]/g, to);
|
|
358
|
+
}
|
|
359
|
+
function mergeFormModels(formModels) {
|
|
360
|
+
const res = [];
|
|
361
|
+
for (const formModel of formModels) {
|
|
362
|
+
for (const subModel of formModel) {
|
|
363
|
+
const index = res.findIndex(t => t.id == subModel.id);
|
|
364
|
+
if (index >= 0) {
|
|
365
|
+
res[index] = subModel;
|
|
366
|
+
continue;
|
|
367
|
+
}
|
|
368
|
+
res.push(subModel);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
return res;
|
|
372
|
+
}
|
|
373
|
+
function collectPathAble(start, getter) {
|
|
374
|
+
if (!start || !getter(start))
|
|
375
|
+
return [];
|
|
376
|
+
const parts = [];
|
|
377
|
+
let currentPath = start;
|
|
378
|
+
while (currentPath) {
|
|
379
|
+
const val = getter(currentPath);
|
|
380
|
+
if (val) {
|
|
381
|
+
parts.unshift(val);
|
|
382
|
+
}
|
|
383
|
+
currentPath = currentPath.parent;
|
|
384
|
+
}
|
|
385
|
+
return parts;
|
|
386
|
+
}
|
|
387
|
+
function getDynamicPath(start) {
|
|
388
|
+
return collectPathAble(start, t => t.id).join(".");
|
|
389
|
+
}
|
|
390
|
+
const MIN_INPUT_NUM = -999999999;
|
|
391
|
+
const MAX_INPUT_NUM = 999999999;
|
|
392
|
+
const EDITOR_FORMATS = ["php", "json", "html", "css", "scss"];
|
|
393
|
+
|
|
394
|
+
function validateJSON(control) {
|
|
395
|
+
const value = control.value;
|
|
396
|
+
if (!value)
|
|
397
|
+
return null;
|
|
398
|
+
try {
|
|
399
|
+
JSON.parse(value);
|
|
400
|
+
return null;
|
|
401
|
+
}
|
|
402
|
+
catch (e) {
|
|
403
|
+
return { json: true };
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
function validateRequiredTranslation(control) {
|
|
407
|
+
const value = control.value;
|
|
408
|
+
if (!value || value.length == 0)
|
|
409
|
+
return { requiredTranslation: true };
|
|
410
|
+
return value.findIndex(t => (t.lang == "de" || t.lang == "en") && !t.translation) < 0
|
|
411
|
+
? null
|
|
412
|
+
: { requiredTranslation: true };
|
|
413
|
+
}
|
|
414
|
+
function validatePhone(control) {
|
|
415
|
+
const value = control.value;
|
|
416
|
+
if (!value)
|
|
417
|
+
return Promise.resolve(null);
|
|
418
|
+
const phoneRegexp = /^(?:\d){10,12}$/;
|
|
419
|
+
return phoneRegexp.test(value) ? null : { phone: true };
|
|
420
|
+
}
|
|
421
|
+
function validateItemsMinLength(minLength) {
|
|
422
|
+
return (control) => {
|
|
423
|
+
const value = control.value;
|
|
424
|
+
return (Array.isArray(value) && value.every(v => typeof v == "string" && v.length >= minLength))
|
|
425
|
+
? null : { itemsMinLength: minLength };
|
|
426
|
+
};
|
|
427
|
+
}
|
|
428
|
+
function validateItemsMaxLength(maxLength) {
|
|
429
|
+
return (control) => {
|
|
430
|
+
const value = control.value;
|
|
431
|
+
return (Array.isArray(value) && value.every(v => typeof v == "string" && v.length <= maxLength))
|
|
432
|
+
? null : { itemsMaxLength: maxLength };
|
|
433
|
+
};
|
|
434
|
+
}
|
|
435
|
+
function validateItemsMinValue(min) {
|
|
436
|
+
return (control) => {
|
|
437
|
+
const value = control.value;
|
|
438
|
+
return (Array.isArray(value) && value.every(v => typeof v == "number" && v >= min))
|
|
439
|
+
? null : { itemsMinValue: min };
|
|
440
|
+
};
|
|
441
|
+
}
|
|
442
|
+
function validateItemsMaxValue(max) {
|
|
443
|
+
return (control) => {
|
|
444
|
+
const value = control.value;
|
|
445
|
+
return (Array.isArray(value) && value.every(v => typeof v == "number" && v <= max))
|
|
446
|
+
? null : { itemsMaxValue: max };
|
|
447
|
+
};
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
const indexLabels = ["$ix", "$pix"];
|
|
451
|
+
class FormSubject extends Subject {
|
|
452
|
+
notifyCallback;
|
|
453
|
+
constructor(notifyCallback) {
|
|
454
|
+
super();
|
|
455
|
+
this.notifyCallback = notifyCallback;
|
|
456
|
+
}
|
|
457
|
+
handleNotifiedValue(controlModel, control, val) {
|
|
458
|
+
val.then(v => this.next(v));
|
|
459
|
+
}
|
|
460
|
+
notify(controlModel, control, root) {
|
|
461
|
+
const indexes = {};
|
|
462
|
+
let path = controlModel;
|
|
463
|
+
let ix = 0;
|
|
464
|
+
while (path) {
|
|
465
|
+
if (!isNaN(path.index)) {
|
|
466
|
+
const key = indexLabels[ix++] || `$pix${ix}`;
|
|
467
|
+
indexes[key] = path.index;
|
|
468
|
+
}
|
|
469
|
+
path = path.parent;
|
|
470
|
+
}
|
|
471
|
+
let value = this.notifyCallback(controlModel, control, root, indexes);
|
|
472
|
+
if (!(value instanceof Promise)) {
|
|
473
|
+
value = Promise.resolve(value);
|
|
474
|
+
}
|
|
475
|
+
this.handleNotifiedValue(controlModel, control, value);
|
|
476
|
+
}
|
|
477
|
+
}
|
|
478
|
+
|
|
479
|
+
class FormSelectSubject extends FormSubject {
|
|
480
|
+
handleNotifiedValue(controlModel, control, val) {
|
|
481
|
+
val.then(options => {
|
|
482
|
+
if (options.length == 0) {
|
|
483
|
+
this.next(options);
|
|
484
|
+
return;
|
|
485
|
+
}
|
|
486
|
+
const currentVal = control.value;
|
|
487
|
+
if (controlModel.multiple) {
|
|
488
|
+
const correctVal = (currentVal || []).filter(t => options.findIndex(o => o.value == t) >= 0);
|
|
489
|
+
if (correctVal.length !== currentVal?.length) {
|
|
490
|
+
control.setValue(correctVal, { onlySelf: true, emitEvent: false });
|
|
491
|
+
}
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
const option = options.find(t => t.value == currentVal);
|
|
495
|
+
if (!option) {
|
|
496
|
+
control.setValue(controlModel.allowEmpty ? null : options[0]?.value ?? null, { onlySelf: true, emitEvent: false });
|
|
497
|
+
}
|
|
498
|
+
}
|
|
499
|
+
this.next(options);
|
|
500
|
+
});
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
function getFormValidationErrors(controls, parentPath = "") {
|
|
505
|
+
const errors = [];
|
|
506
|
+
Object.entries(controls).forEach(([name, control], ix) => {
|
|
507
|
+
const path = !parentPath ? name : `${parentPath}.${name}`;
|
|
508
|
+
if (control instanceof FormGroup) {
|
|
509
|
+
getFormValidationErrors(control.controls, path).forEach(error => errors.push(error));
|
|
510
|
+
return;
|
|
511
|
+
}
|
|
512
|
+
if (control instanceof FormArray) {
|
|
513
|
+
control.controls.forEach((control, ix) => {
|
|
514
|
+
getFormValidationErrors(control.controls, `${path}.${ix}`).forEach(error => errors.push(error));
|
|
515
|
+
});
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
Object.entries(control.errors || {}).forEach(([errorKey, errorValue]) => {
|
|
519
|
+
errors.push({ control, path, errorKey, errorValue });
|
|
520
|
+
});
|
|
521
|
+
});
|
|
522
|
+
return errors;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
class DynamicFormService extends DynamicFormService$1 {
|
|
526
|
+
openApi;
|
|
527
|
+
injector;
|
|
528
|
+
get api() {
|
|
529
|
+
return this.openApi.api;
|
|
530
|
+
}
|
|
531
|
+
get language() {
|
|
532
|
+
return this.api.language;
|
|
533
|
+
}
|
|
534
|
+
schemas;
|
|
535
|
+
constructor(cs, vs, openApi, injector) {
|
|
536
|
+
super(cs, vs);
|
|
537
|
+
this.openApi = openApi;
|
|
538
|
+
this.injector = injector;
|
|
539
|
+
}
|
|
540
|
+
patchGroup(value, formModel, formGroup) {
|
|
541
|
+
value = ObjectUtils.copy(value);
|
|
542
|
+
this.patchValueRecursive(value, formModel, formGroup);
|
|
543
|
+
formGroup.patchValue(value);
|
|
544
|
+
this.detectChanges();
|
|
545
|
+
}
|
|
546
|
+
patchForm(value, component) {
|
|
547
|
+
value = ObjectUtils.copy(value);
|
|
548
|
+
this.patchValueRecursive(value, component.model, component.group);
|
|
549
|
+
component.group.patchValue(value);
|
|
550
|
+
this.detectChanges(component);
|
|
551
|
+
}
|
|
552
|
+
serialize(formModel, formGroup) {
|
|
553
|
+
return this.serializeRecursive(formModel, formGroup);
|
|
554
|
+
}
|
|
555
|
+
notifyChanges(formModel, formGroup) {
|
|
556
|
+
this.notifyChangesRecursive(formModel, formGroup, formModel);
|
|
557
|
+
}
|
|
558
|
+
showErrors(form) {
|
|
559
|
+
this.showErrorsForGroup(form.group);
|
|
560
|
+
this.detectChanges(form);
|
|
561
|
+
}
|
|
562
|
+
getErrors(form) {
|
|
563
|
+
this.showErrors(form);
|
|
564
|
+
return new Promise(resolve => {
|
|
565
|
+
setTimeout(() => {
|
|
566
|
+
resolve(getFormValidationErrors(form.group.controls, ""));
|
|
567
|
+
}, 500);
|
|
568
|
+
});
|
|
569
|
+
}
|
|
570
|
+
patchValueRecursive(value, formModel, formGroup) {
|
|
571
|
+
if (!value)
|
|
572
|
+
return;
|
|
573
|
+
formModel?.forEach(subModel => {
|
|
574
|
+
const key = subModel.id;
|
|
575
|
+
const subValue = value[key];
|
|
576
|
+
const subControl = this.findControlByModel(subModel, formGroup);
|
|
577
|
+
if (subModel instanceof DynamicSelectModel && ObjectUtils.isObject(subValue)) {
|
|
578
|
+
value[key] = subValue.id || subValue._id || subValue;
|
|
579
|
+
return;
|
|
580
|
+
}
|
|
581
|
+
if (subModel instanceof DynamicDatePickerModel) {
|
|
582
|
+
value[key] = this.convertToDate(subValue);
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (subModel instanceof DynamicFormArrayModel) {
|
|
586
|
+
const length = Array.isArray(subValue) ? subValue.length : 0;
|
|
587
|
+
const subArray = subControl;
|
|
588
|
+
while (subModel.size > length) {
|
|
589
|
+
this.removeFormArrayGroup(0, subArray, subModel);
|
|
590
|
+
}
|
|
591
|
+
while (subModel.size < length) {
|
|
592
|
+
this.insertFormArrayGroup(subModel.size, subArray, subModel);
|
|
593
|
+
}
|
|
594
|
+
for (let i = 0; i < length; i++) {
|
|
595
|
+
const itemModel = subModel.get(i);
|
|
596
|
+
this.patchValueRecursive(subValue[i], itemModel.group, subArray.at(i));
|
|
597
|
+
}
|
|
598
|
+
return;
|
|
599
|
+
}
|
|
600
|
+
if (subModel instanceof DynamicFormGroupModel) {
|
|
601
|
+
this.patchValueRecursive(subValue, subModel.group, subControl);
|
|
602
|
+
}
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
async serializeRecursive(formModel, formGroup) {
|
|
606
|
+
const result = {};
|
|
607
|
+
if (!formModel || !formGroup || !formGroup.value)
|
|
608
|
+
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;
|
|
613
|
+
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.serializeRecursive(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;
|
|
634
|
+
continue;
|
|
635
|
+
}
|
|
636
|
+
if (subModel instanceof DynamicFormGroupModel) {
|
|
637
|
+
result[subModel.id] = await this.serializeRecursive(subModel.group, subControl);
|
|
638
|
+
continue;
|
|
639
|
+
}
|
|
640
|
+
result[subModel.id] = subControl.value;
|
|
641
|
+
}
|
|
642
|
+
return result;
|
|
643
|
+
}
|
|
644
|
+
notifyChangesRecursive(formModel, formGroup, root) {
|
|
645
|
+
if (!formModel || !formGroup)
|
|
646
|
+
return;
|
|
647
|
+
for (const i in formModel) {
|
|
648
|
+
const subModel = formModel[i];
|
|
649
|
+
const subControl = this.findControlByModel(subModel, formGroup);
|
|
650
|
+
if (subModel instanceof DynamicFormArrayModel) {
|
|
651
|
+
const length = Array.isArray(subControl.value) ? subControl.value.length : 0;
|
|
652
|
+
const subArray = subControl;
|
|
653
|
+
for (let i = 0; i < length; i++) {
|
|
654
|
+
const itemModel = subModel.get(i);
|
|
655
|
+
this.notifyChangesRecursive(itemModel.group, subArray.at(i), root);
|
|
656
|
+
}
|
|
657
|
+
continue;
|
|
658
|
+
}
|
|
659
|
+
if (subModel instanceof DynamicFormGroupModel) {
|
|
660
|
+
this.notifyChangesRecursive(subModel.group, subControl, root);
|
|
661
|
+
continue;
|
|
662
|
+
}
|
|
663
|
+
this.updateSelectOptions(subModel, subControl, root);
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
updateSelectOptions(formControlModel, formControl, root) {
|
|
667
|
+
if (formControlModel instanceof DynamicSelectModel) {
|
|
668
|
+
let options = formControlModel.options$;
|
|
669
|
+
if (options instanceof FormSubject) {
|
|
670
|
+
options.notify(formControlModel, formControl, root);
|
|
671
|
+
return;
|
|
672
|
+
}
|
|
673
|
+
while (options instanceof Subject && options.source) {
|
|
674
|
+
options = options.source;
|
|
675
|
+
if (options instanceof FormSubject) {
|
|
676
|
+
options.notify(formControlModel, formControl, root);
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
showErrorsForGroup(formGroup) {
|
|
682
|
+
if (!formGroup)
|
|
683
|
+
return;
|
|
684
|
+
formGroup.markAsTouched({ onlySelf: true });
|
|
685
|
+
const controls = Object.keys(formGroup.controls).map(id => formGroup.controls[id]);
|
|
686
|
+
this.showErrorsForControls(controls);
|
|
687
|
+
}
|
|
688
|
+
showErrorsForControls(controls) {
|
|
689
|
+
controls.forEach(control => {
|
|
690
|
+
if (control instanceof FormGroup) {
|
|
691
|
+
this.showErrorsForGroup(control);
|
|
692
|
+
return;
|
|
693
|
+
}
|
|
694
|
+
control.markAsTouched({ onlySelf: true });
|
|
695
|
+
if (control instanceof FormArray) {
|
|
696
|
+
this.showErrorsForControls(control.controls);
|
|
697
|
+
}
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
convertToDate(value) {
|
|
701
|
+
if (ObjectUtils.isNullOrUndefined(value))
|
|
702
|
+
return null;
|
|
703
|
+
const date = ObjectUtils.isDate(value)
|
|
704
|
+
? value
|
|
705
|
+
: new Date(value);
|
|
706
|
+
return isNaN(date) ? new Date() : date;
|
|
707
|
+
}
|
|
708
|
+
async getFormModelForSchema(name, customizeModel) {
|
|
709
|
+
return (await this.getFormGroupModelForSchema(name, customizeModel)).group;
|
|
710
|
+
}
|
|
711
|
+
async getFormGroupModelForSchema(name, customizeModel) {
|
|
712
|
+
this.api.cache = {};
|
|
713
|
+
this.schemas = await this.openApi.getSchemas();
|
|
714
|
+
const fieldSets = [];
|
|
715
|
+
const customizeModels = async (property, schema, modelType, config) => {
|
|
716
|
+
const model = new modelType(config);
|
|
717
|
+
if (model instanceof DynamicFormValueControlModel) {
|
|
718
|
+
model.value = (model instanceof DynamicDatePickerModel)
|
|
719
|
+
? this.convertToDate(property.default) : property.default;
|
|
720
|
+
}
|
|
721
|
+
if (!ObjectUtils.isFunction(customizeModel))
|
|
722
|
+
return [model];
|
|
723
|
+
let res = customizeModel(property, schema, model, config, this.injector);
|
|
724
|
+
if (!res)
|
|
725
|
+
return [model];
|
|
726
|
+
if (res instanceof Promise) {
|
|
727
|
+
res = await res;
|
|
728
|
+
}
|
|
729
|
+
return Array.isArray(res) ? res : [res];
|
|
730
|
+
};
|
|
731
|
+
const schema = this.schemas[name];
|
|
732
|
+
const controls = await this.getFormModelForSchemaDef(schema, fieldSets, customizeModels);
|
|
733
|
+
const idFields = [
|
|
734
|
+
createFormInput("id", { hidden: true }),
|
|
735
|
+
createFormInput("_id", { hidden: true })
|
|
736
|
+
].filter(t => !controls.some(c => c.id == t.id));
|
|
737
|
+
const config = {
|
|
738
|
+
id: "root",
|
|
739
|
+
group: [
|
|
740
|
+
// -- Hidden id fields --
|
|
741
|
+
...idFields,
|
|
742
|
+
// -- Main form controls --
|
|
743
|
+
...controls
|
|
744
|
+
],
|
|
745
|
+
fieldSets
|
|
746
|
+
};
|
|
747
|
+
const root = await customizeModels({
|
|
748
|
+
id: "root",
|
|
749
|
+
type: "object",
|
|
750
|
+
properties: schema.properties
|
|
751
|
+
}, schema, DynamicFormGroupModel, config);
|
|
752
|
+
// Check if the customized root wrapper returned an array
|
|
753
|
+
if (Array.isArray(root)) {
|
|
754
|
+
controls.length = 0;
|
|
755
|
+
for (const model of root) {
|
|
756
|
+
if (model instanceof DynamicFormGroupModel && model.id === "root") {
|
|
757
|
+
return model;
|
|
758
|
+
}
|
|
759
|
+
else {
|
|
760
|
+
controls.push(model);
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return new DynamicFormGroupModel({
|
|
765
|
+
...config,
|
|
766
|
+
group: controls
|
|
767
|
+
});
|
|
768
|
+
}
|
|
769
|
+
async getFormModelForSchemaDef(schema, fieldSets, customizeModels) {
|
|
770
|
+
if (!schema)
|
|
771
|
+
return [];
|
|
772
|
+
const keys = Object.keys(schema.properties || {});
|
|
773
|
+
const controls = [];
|
|
774
|
+
for (const p of keys) {
|
|
775
|
+
const property = schema.properties[p];
|
|
776
|
+
const fsName = property.hidden ? null : String(property.fieldSet || "");
|
|
777
|
+
if (fsName) {
|
|
778
|
+
const fs = fieldSets.find(t => t.id === fsName);
|
|
779
|
+
if (fs) {
|
|
780
|
+
fs.fields.push(p);
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
fieldSets.push({ id: fsName, legend: `legend.${fsName}`, fields: [p] });
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
const models = await this.getFormControlModels(property, schema, customizeModels);
|
|
787
|
+
controls.push(...models);
|
|
788
|
+
}
|
|
789
|
+
return controls.filter(t => null !== t);
|
|
790
|
+
}
|
|
791
|
+
checkIsEditorProperty(property) {
|
|
792
|
+
if (!property.format)
|
|
793
|
+
return false;
|
|
794
|
+
return EDITOR_FORMATS.indexOf(property.format) >= 0 || property.format.endsWith("script");
|
|
795
|
+
}
|
|
796
|
+
async getFormControlModels(property, schema, customizeModels) {
|
|
797
|
+
const $enum = property.items?.enum || property.enum;
|
|
798
|
+
if (Array.isArray($enum) || isStringWithVal(property.optionsPath) || isStringWithVal(property.endpoint)) {
|
|
799
|
+
return customizeModels(property, schema, DynamicSelectModel, this.getFormSelectConfig(property, schema));
|
|
800
|
+
}
|
|
801
|
+
switch (property.type) {
|
|
802
|
+
case "string":
|
|
803
|
+
case "number":
|
|
804
|
+
case "integer":
|
|
805
|
+
case "textarea":
|
|
806
|
+
if (this.checkIsEditorProperty(property)) {
|
|
807
|
+
return customizeModels(property, schema, DynamicEditorModel, this.getFormEditorConfig(property, schema));
|
|
808
|
+
}
|
|
809
|
+
if (property.format == "textarea") {
|
|
810
|
+
return customizeModels(property, schema, DynamicTextAreaModel, this.getFormTextareaConfig(property, schema));
|
|
811
|
+
}
|
|
812
|
+
if (property.format == "date") {
|
|
813
|
+
return customizeModels(property, schema, DynamicDatePickerModel, this.getFormDatepickerConfig(property, schema));
|
|
814
|
+
}
|
|
815
|
+
return customizeModels(property, schema, DynamicInputModel, this.getFormInputConfig(property, schema));
|
|
816
|
+
case "object":
|
|
817
|
+
return customizeModels(property, schema, DynamicEditorModel, this.getFormEditorConfig(property, schema));
|
|
818
|
+
case "boolean":
|
|
819
|
+
return customizeModels(property, schema, DynamicCheckboxModel, this.getFormCheckboxConfig(property, schema));
|
|
820
|
+
case "array":
|
|
821
|
+
if (findRefs(property).length > 0) {
|
|
822
|
+
return customizeModels(property, schema, DynamicFormArrayModel, await this.getFormArrayConfig(property, schema, customizeModels));
|
|
823
|
+
}
|
|
824
|
+
else {
|
|
825
|
+
return customizeModels(property, schema, DynamicInputModel, this.getFormInputConfig(property, schema));
|
|
826
|
+
}
|
|
827
|
+
case "file":
|
|
828
|
+
return customizeModels(property, schema, DynamicFileUploadModel, this.getFormUploadConfig(property, schema));
|
|
829
|
+
}
|
|
830
|
+
if (findRefs(property).length > 0) {
|
|
831
|
+
return customizeModels(property, schema, DynamicFormGroupModel, await this.getFormGroupConfig(property, schema, customizeModels));
|
|
832
|
+
}
|
|
833
|
+
return [];
|
|
834
|
+
}
|
|
835
|
+
findModelByPath(parent, path) {
|
|
836
|
+
if (path.length == 0)
|
|
837
|
+
return parent;
|
|
838
|
+
const next = path.shift();
|
|
839
|
+
if (Array.isArray(parent)) {
|
|
840
|
+
return this.findModelByPath(parent.find(t => t.id == next), path);
|
|
841
|
+
}
|
|
842
|
+
if (parent instanceof DynamicFormGroupModel || parent instanceof DynamicFormArrayGroupModel) {
|
|
843
|
+
return this.findModelByPath(parent.group.find(t => t.id == next), path);
|
|
844
|
+
}
|
|
845
|
+
if (parent instanceof DynamicFormArrayModel) {
|
|
846
|
+
return this.findModelByPath(parent.groups.find(t => t.index == next), path);
|
|
847
|
+
}
|
|
848
|
+
return parent;
|
|
849
|
+
}
|
|
850
|
+
getFormControlConfig(property, schema) {
|
|
851
|
+
const validators = this.getValidators(property, schema);
|
|
852
|
+
const errorMessages = Object.keys(validators).reduce((res, key) => {
|
|
853
|
+
res[key] = `error.${key}`;
|
|
854
|
+
return res;
|
|
855
|
+
}, {});
|
|
856
|
+
return {
|
|
857
|
+
id: property.id,
|
|
858
|
+
label: ObjectUtils.isString(property.label) ? property.label : property.id,
|
|
859
|
+
hidden: property.hidden,
|
|
860
|
+
disabled: property.disabled,
|
|
861
|
+
validators,
|
|
862
|
+
errorMessages,
|
|
863
|
+
additional: Object.assign({}, property)
|
|
864
|
+
};
|
|
865
|
+
}
|
|
866
|
+
async getFormArrayConfig(property, schema, customizeModels) {
|
|
867
|
+
const fieldSets = [];
|
|
868
|
+
const subSchemas = findRefs(property).map(ref => this.schemas[ref]);
|
|
869
|
+
const subModels = await Promise.all(subSchemas.map(s => this.getFormModelForSchemaDef(s, fieldSets, customizeModels)));
|
|
870
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
871
|
+
groupFactory: () => mergeFormModels(ObjectUtils.copy(subModels)),
|
|
872
|
+
initialCount: property.initialCount || 0,
|
|
873
|
+
sortable: property.sortable || false,
|
|
874
|
+
useTabs: property.useTabs || false,
|
|
875
|
+
addItem: property.addItem !== false,
|
|
876
|
+
insertItem: property.insertItem !== false,
|
|
877
|
+
cloneItem: property.cloneItem !== false,
|
|
878
|
+
moveItem: property.moveItem !== false,
|
|
879
|
+
removeItem: property.removeItem !== false,
|
|
880
|
+
clearItems: property.clearItems !== false
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
async getFormGroupConfig(property, schema, customizeModels) {
|
|
884
|
+
const fieldSets = [];
|
|
885
|
+
const subSchemas = findRefs(property).map(ref => this.schemas[ref]);
|
|
886
|
+
const subModels = await Promise.all(subSchemas.map(s => this.getFormModelForSchemaDef(s, fieldSets, customizeModels)));
|
|
887
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
888
|
+
fieldSets,
|
|
889
|
+
group: mergeFormModels(subModels)
|
|
890
|
+
});
|
|
891
|
+
}
|
|
892
|
+
getFormInputConfig(property, schema) {
|
|
893
|
+
let inputType = StringUtils.has(property.id, "password", "Password") ? "password" : (property.format || property.items?.type || property.type);
|
|
894
|
+
switch (inputType) {
|
|
895
|
+
case "string":
|
|
896
|
+
inputType = "text";
|
|
897
|
+
break;
|
|
898
|
+
case "boolean":
|
|
899
|
+
inputType = "checkbox";
|
|
900
|
+
break;
|
|
901
|
+
case "textarea":
|
|
902
|
+
inputType = "textarea";
|
|
903
|
+
break;
|
|
904
|
+
case "integer":
|
|
905
|
+
inputType = "number";
|
|
906
|
+
break;
|
|
907
|
+
}
|
|
908
|
+
const sub = property.type == "array" ? property.items || property : property;
|
|
909
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
910
|
+
inputType,
|
|
911
|
+
autoComplete: property.autoComplete || "off",
|
|
912
|
+
multiple: property.type == "array",
|
|
913
|
+
accept: ObjectUtils.isString(property.accept) ? property.accept : null,
|
|
914
|
+
mask: ObjectUtils.isString(property.mask) ? property.mask : null,
|
|
915
|
+
pattern: ObjectUtils.isString(property.pattern) ? property.pattern : null,
|
|
916
|
+
step: isNaN(sub.step) ? (isNaN(property.step) ? 1 : property.step) : sub.step,
|
|
917
|
+
min: isNaN(sub.minimum) ? MIN_INPUT_NUM : sub.minimum,
|
|
918
|
+
max: isNaN(sub.maximum) ? MAX_INPUT_NUM : sub.maximum,
|
|
919
|
+
minLength: isNaN(sub.minLength) ? 0 : sub.minLength,
|
|
920
|
+
maxLength: isNaN(sub.maxLength) ? MAX_INPUT_NUM : sub.maxLength,
|
|
921
|
+
placeholder: property.placeholder || ""
|
|
922
|
+
});
|
|
923
|
+
}
|
|
924
|
+
getFormEditorConfig(property, schema) {
|
|
925
|
+
const sub = property.type == "array" ? property.items || property : property;
|
|
926
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
927
|
+
inputType: property.format || "json",
|
|
928
|
+
convertObject: property.type !== "string",
|
|
929
|
+
autoComplete: property.autoComplete || "off",
|
|
930
|
+
multiple: property.type == "array",
|
|
931
|
+
accept: ObjectUtils.isString(property.accept) ? property.accept : null,
|
|
932
|
+
mask: ObjectUtils.isString(property.mask) ? property.mask : null,
|
|
933
|
+
pattern: ObjectUtils.isString(property.pattern) ? property.pattern : null,
|
|
934
|
+
step: isNaN(sub.step) ? (isNaN(property.step) ? 1 : property.step) : sub.step,
|
|
935
|
+
minLength: isNaN(sub.minLength) ? 0 : sub.minLength,
|
|
936
|
+
maxLength: isNaN(sub.maxLength) ? MAX_INPUT_NUM : sub.maxLength,
|
|
937
|
+
placeholder: property.placeholder || ""
|
|
938
|
+
});
|
|
939
|
+
}
|
|
940
|
+
getFormTextareaConfig(property, schema) {
|
|
941
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
942
|
+
cols: property.cols || null,
|
|
943
|
+
rows: property.rows || 10,
|
|
944
|
+
wrap: property.wrap || false,
|
|
945
|
+
autoComplete: property.autoComplete || "off",
|
|
946
|
+
multiple: property.type == "array",
|
|
947
|
+
minLength: isNaN(property.minLength) ? 0 : property.minLength,
|
|
948
|
+
maxLength: isNaN(property.maxLength) ? MAX_INPUT_NUM : property.maxLength,
|
|
949
|
+
placeholder: property.placeholder || ""
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
getFormDatepickerConfig(property, schema) {
|
|
953
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
954
|
+
format: property.dateFormat || "dd.MM.yyyy",
|
|
955
|
+
min: this.convertToDate(property.min),
|
|
956
|
+
max: this.convertToDate(property.max),
|
|
957
|
+
});
|
|
958
|
+
}
|
|
959
|
+
getFormSelectOptions(property, schema) {
|
|
960
|
+
const $enum = property.items?.enum || property.enum;
|
|
961
|
+
if (Array.isArray($enum)) {
|
|
962
|
+
return new FormSelectSubject((selectModel, formControl) => {
|
|
963
|
+
const options = $enum.map(value => {
|
|
964
|
+
const label = property.translatable ? `${property.id}.${value}` : `${value}`;
|
|
965
|
+
return { value, label };
|
|
966
|
+
});
|
|
967
|
+
return this.fixSelectOptions(selectModel, formControl, options);
|
|
968
|
+
});
|
|
969
|
+
}
|
|
970
|
+
if (isStringWithVal(property.optionsPath)) {
|
|
971
|
+
return new FormSelectSubject(async (selectModel, control, root, indexes) => {
|
|
972
|
+
let path = property.optionsPath;
|
|
973
|
+
let target = control;
|
|
974
|
+
let model = selectModel;
|
|
975
|
+
if (path.startsWith("$root")) {
|
|
976
|
+
path = path.substring(5);
|
|
977
|
+
while (target.parent) {
|
|
978
|
+
target = target.parent;
|
|
979
|
+
}
|
|
980
|
+
model = root;
|
|
981
|
+
}
|
|
982
|
+
while (path.startsWith(".")) {
|
|
983
|
+
path = path.substring(1);
|
|
984
|
+
if (target.parent) {
|
|
985
|
+
target = target.parent;
|
|
986
|
+
}
|
|
987
|
+
model = model.parent || root;
|
|
988
|
+
}
|
|
989
|
+
Object.keys(indexes).forEach(key => {
|
|
990
|
+
path = path.replace(key, indexes[key]);
|
|
991
|
+
});
|
|
992
|
+
model = this.findModelByPath(model, path.split("."));
|
|
993
|
+
const modelOptions = model instanceof DynamicSelectModel
|
|
994
|
+
? await firstValueFrom(model.options$) :
|
|
995
|
+
[];
|
|
996
|
+
const value = ObjectUtils.getValue(target.value, path);
|
|
997
|
+
const options = (!ObjectUtils.isArray(value) ? [] : value).map(value => {
|
|
998
|
+
const modelOption = modelOptions.find(t => t.value == value);
|
|
999
|
+
return { value, label: modelOption?.label || value };
|
|
1000
|
+
});
|
|
1001
|
+
return this.fixSelectOptions(selectModel, control, options);
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
return new FormSelectSubject(async (selectModel, control) => {
|
|
1005
|
+
console.log(control.root?.value, "form select subject");
|
|
1006
|
+
const entries = Object.entries(control.root?.value || {});
|
|
1007
|
+
const endpoint = entries.reduce((res, [key, value]) => {
|
|
1008
|
+
return res.replace(new RegExp(`$${key}`, "gi"), `${value}`);
|
|
1009
|
+
}, `${property.endpoint}`);
|
|
1010
|
+
this.api.cache[endpoint] = this.api.cache[endpoint] || this.api.list(endpoint, this.api.makeListParams(1, -1)).then(result => {
|
|
1011
|
+
const items = ObjectUtils.isArray(result)
|
|
1012
|
+
? result
|
|
1013
|
+
: (ObjectUtils.isArray(result.items) ? result.items : []);
|
|
1014
|
+
return items.map(i => {
|
|
1015
|
+
const item = ObjectUtils.isObject(i) ? i : { id: i };
|
|
1016
|
+
return {
|
|
1017
|
+
...item,
|
|
1018
|
+
value: item.id || item._id,
|
|
1019
|
+
label: item[property.labelField] || item.label || item.id || item._id
|
|
1020
|
+
};
|
|
1021
|
+
});
|
|
1022
|
+
});
|
|
1023
|
+
const options = (await this.api.cache[endpoint]).map(t => Object.assign({}, t));
|
|
1024
|
+
return this.fixSelectOptions(selectModel, control, options);
|
|
1025
|
+
});
|
|
1026
|
+
}
|
|
1027
|
+
getFormSelectConfig(property, schema) {
|
|
1028
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
1029
|
+
options: this.getFormSelectOptions(property, schema),
|
|
1030
|
+
multiple: property.type == "array",
|
|
1031
|
+
groupBy: property.groupBy,
|
|
1032
|
+
inline: property.inline,
|
|
1033
|
+
allowEmpty: property.allowEmpty,
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
getFormUploadConfig(property, schema) {
|
|
1037
|
+
const url = this.api.url(property.url || "assets");
|
|
1038
|
+
const { accept, autoUpload, maxSize, minSize, removeUrl, showFileList } = property;
|
|
1039
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
1040
|
+
url,
|
|
1041
|
+
accept,
|
|
1042
|
+
autoUpload,
|
|
1043
|
+
maxSize,
|
|
1044
|
+
minSize,
|
|
1045
|
+
removeUrl,
|
|
1046
|
+
showFileList
|
|
1047
|
+
});
|
|
1048
|
+
}
|
|
1049
|
+
getFormCheckboxConfig(property, schema) {
|
|
1050
|
+
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
1051
|
+
indeterminate: property.indeterminate || false
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
cloneFormArrayGroup(index, formArray, formArrayModel) {
|
|
1055
|
+
this.insertFormArrayGroup(index, formArray, formArrayModel);
|
|
1056
|
+
this.patchGroup(formArray.at(index + 1).value, formArrayModel.groups[index].group, formArray.at(index));
|
|
1057
|
+
formArrayModel.filterGroups();
|
|
1058
|
+
}
|
|
1059
|
+
async fixSelectOptions(model, control, options) {
|
|
1060
|
+
if (!options)
|
|
1061
|
+
return [];
|
|
1062
|
+
for (const option of options) {
|
|
1063
|
+
option.classes = [option.classes, model.getClasses(option, model, control, this.injector)].filter(isStringWithVal).join(" ");
|
|
1064
|
+
option.label = await this.language.getTranslation(option.label);
|
|
1065
|
+
}
|
|
1066
|
+
return options;
|
|
1067
|
+
}
|
|
1068
|
+
getValidators(property, schema) {
|
|
1069
|
+
const validators = {};
|
|
1070
|
+
if (ObjectUtils.isArray(schema.required) && schema.required.indexOf(property.id) >= 0) {
|
|
1071
|
+
validators.required = null;
|
|
1072
|
+
}
|
|
1073
|
+
this.addPropertyValidators(validators, property);
|
|
1074
|
+
this.addItemsValidators(validators, property.items);
|
|
1075
|
+
return validators;
|
|
1076
|
+
}
|
|
1077
|
+
addPropertyValidators(validators, property) {
|
|
1078
|
+
if (!property)
|
|
1079
|
+
return;
|
|
1080
|
+
if (!isNaN(property.minLength)) {
|
|
1081
|
+
validators.minLength = property.minLength;
|
|
1082
|
+
}
|
|
1083
|
+
if (!isNaN(property.maxLength)) {
|
|
1084
|
+
validators.maxLength = property.maxLength;
|
|
1085
|
+
}
|
|
1086
|
+
if (!isNaN(property.minimum)) {
|
|
1087
|
+
validators.min = property.minimum;
|
|
1088
|
+
}
|
|
1089
|
+
if (!isNaN(property.maximum)) {
|
|
1090
|
+
validators.max = property.maximum;
|
|
1091
|
+
}
|
|
1092
|
+
switch (property.format) {
|
|
1093
|
+
case "email":
|
|
1094
|
+
validators.email = null;
|
|
1095
|
+
break;
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
addItemsValidators(validators, items) {
|
|
1099
|
+
if (!items)
|
|
1100
|
+
return;
|
|
1101
|
+
if (!isNaN(items.minLength)) {
|
|
1102
|
+
validators.itemsMinLength = items.minLength;
|
|
1103
|
+
}
|
|
1104
|
+
if (!isNaN(items.maxLength)) {
|
|
1105
|
+
validators.itemsMaxLength = items.maxLength;
|
|
1106
|
+
}
|
|
1107
|
+
if (!isNaN(items.minimum)) {
|
|
1108
|
+
validators.itemsMinValue = items.minimum;
|
|
1109
|
+
}
|
|
1110
|
+
if (!isNaN(items.maximum)) {
|
|
1111
|
+
validators.itemsMaxValue = items.maximum;
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
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 });
|
|
1115
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicFormService });
|
|
1116
|
+
}
|
|
1117
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicFormService, decorators: [{
|
|
1118
|
+
type: Injectable
|
|
1119
|
+
}], ctorParameters: () => [{ type: i1.DynamicFormComponentService }, { type: i1.DynamicFormValidationService }, { type: i2.OpenApiService, decorators: [{
|
|
1120
|
+
type: Inject,
|
|
1121
|
+
args: [OpenApiService]
|
|
1122
|
+
}] }, { type: i0.Injector, decorators: [{
|
|
1123
|
+
type: Inject,
|
|
1124
|
+
args: [Injector]
|
|
1125
|
+
}] }] });
|
|
1126
|
+
|
|
1127
|
+
class AsyncSubmitDirective {
|
|
1128
|
+
toaster;
|
|
1129
|
+
cdr;
|
|
1130
|
+
elem;
|
|
1131
|
+
renderer;
|
|
1132
|
+
method;
|
|
1133
|
+
form;
|
|
1134
|
+
context;
|
|
1135
|
+
onSuccess;
|
|
1136
|
+
onError;
|
|
1137
|
+
loading;
|
|
1138
|
+
disabled;
|
|
1139
|
+
callback;
|
|
1140
|
+
onStatusChange;
|
|
1141
|
+
onSubmit;
|
|
1142
|
+
get isDisabled() {
|
|
1143
|
+
return this.disabled;
|
|
1144
|
+
}
|
|
1145
|
+
set isDisabled(value) {
|
|
1146
|
+
this.disabled = value;
|
|
1147
|
+
if (value) {
|
|
1148
|
+
this.renderer.setAttribute(this.elem.nativeElement, "disabled", "disabled");
|
|
1149
|
+
return;
|
|
1150
|
+
}
|
|
1151
|
+
this.renderer.removeAttribute(this.elem.nativeElement, "disabled");
|
|
1152
|
+
}
|
|
1153
|
+
get isLoading() {
|
|
1154
|
+
return this.loading;
|
|
1155
|
+
}
|
|
1156
|
+
constructor(toaster, cdr, elem, renderer) {
|
|
1157
|
+
this.toaster = toaster;
|
|
1158
|
+
this.cdr = cdr;
|
|
1159
|
+
this.elem = elem;
|
|
1160
|
+
this.renderer = renderer;
|
|
1161
|
+
this.onSuccess = new EventEmitter();
|
|
1162
|
+
this.onError = new EventEmitter();
|
|
1163
|
+
if (elem.nativeElement.tagName !== "BUTTON")
|
|
1164
|
+
return;
|
|
1165
|
+
renderer.setAttribute(elem.nativeElement, "type", "button");
|
|
1166
|
+
}
|
|
1167
|
+
ngOnInit() {
|
|
1168
|
+
if (!this.form)
|
|
1169
|
+
return;
|
|
1170
|
+
this.isDisabled = this.form.status !== "VALID";
|
|
1171
|
+
this.cdr.detectChanges();
|
|
1172
|
+
this.onStatusChange = this.form.onStatusChange.subscribe(() => {
|
|
1173
|
+
this.isDisabled = this.form.status !== "VALID";
|
|
1174
|
+
this.cdr.detectChanges();
|
|
1175
|
+
if (!this.callback || this.form.status == "PENDING")
|
|
1176
|
+
return;
|
|
1177
|
+
if (!this.disabled) {
|
|
1178
|
+
this.callback();
|
|
1179
|
+
}
|
|
1180
|
+
this.callback = null;
|
|
1181
|
+
});
|
|
1182
|
+
this.onSubmit = this.form.onSubmit.pipe(debounceTime(200)).subscribe(() => this.callMethod());
|
|
1183
|
+
}
|
|
1184
|
+
ngOnDestroy() {
|
|
1185
|
+
if (this.onStatusChange)
|
|
1186
|
+
this.onStatusChange.unsubscribe();
|
|
1187
|
+
if (this.onSubmit)
|
|
1188
|
+
this.onSubmit.unsubscribe();
|
|
1189
|
+
}
|
|
1190
|
+
click() {
|
|
1191
|
+
this.callback = () => this.callMethod();
|
|
1192
|
+
if (this.form.status === "INVALID") {
|
|
1193
|
+
console.log(getFormValidationErrors(this.form.group.controls));
|
|
1194
|
+
}
|
|
1195
|
+
if (this.form.status !== "VALID" && this.form.status !== "INVALID")
|
|
1196
|
+
return;
|
|
1197
|
+
this.callback();
|
|
1198
|
+
this.callback = null;
|
|
1199
|
+
}
|
|
1200
|
+
callMethod() {
|
|
1201
|
+
if (this.loading)
|
|
1202
|
+
return;
|
|
1203
|
+
this.loading = true;
|
|
1204
|
+
this.method(this.form, this.context).then(result => {
|
|
1205
|
+
this.loading = false;
|
|
1206
|
+
if (result) {
|
|
1207
|
+
this.onSuccess.emit(result);
|
|
1208
|
+
this.toaster.success(result.message, result.context);
|
|
1209
|
+
}
|
|
1210
|
+
}, reason => {
|
|
1211
|
+
if (!reason || !reason.message)
|
|
1212
|
+
throw new Error("Reason must implement IAsyncMessage interface");
|
|
1213
|
+
this.loading = false;
|
|
1214
|
+
this.onError.emit(reason);
|
|
1215
|
+
this.toaster.error(reason.message, reason.context);
|
|
1216
|
+
});
|
|
1217
|
+
}
|
|
1218
|
+
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.ElementRef }, { token: i0.Renderer2 }], target: i0.ɵɵFactoryTarget.Directive });
|
|
1219
|
+
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"], ngImport: i0 });
|
|
1220
|
+
}
|
|
1221
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: AsyncSubmitDirective, decorators: [{
|
|
1222
|
+
type: Directive,
|
|
1223
|
+
args: [{
|
|
1224
|
+
standalone: false,
|
|
1225
|
+
selector: "[async-submit]",
|
|
1226
|
+
exportAs: "async-submit"
|
|
1227
|
+
}]
|
|
1228
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
1229
|
+
type: Inject,
|
|
1230
|
+
args: [TOASTER_SERVICE]
|
|
1231
|
+
}] }, { type: i0.ChangeDetectorRef }, { type: i0.ElementRef }, { type: i0.Renderer2 }], propDecorators: { method: [{
|
|
1232
|
+
type: Input,
|
|
1233
|
+
args: ["async-submit"]
|
|
1234
|
+
}], form: [{
|
|
1235
|
+
type: Input
|
|
1236
|
+
}], context: [{
|
|
1237
|
+
type: Input
|
|
1238
|
+
}], onSuccess: [{
|
|
1239
|
+
type: Output
|
|
1240
|
+
}], onError: [{
|
|
1241
|
+
type: Output
|
|
1242
|
+
}], isDisabled: [{
|
|
1243
|
+
type: HostBinding,
|
|
1244
|
+
args: ["class.disabled"]
|
|
1245
|
+
}], isLoading: [{
|
|
1246
|
+
type: HostBinding,
|
|
1247
|
+
args: ["class.loading"]
|
|
1248
|
+
}], click: [{
|
|
1249
|
+
type: HostListener,
|
|
1250
|
+
args: ["click"]
|
|
1251
|
+
}] } });
|
|
1252
|
+
|
|
1253
|
+
class DynamicBaseFormComponent extends DynamicFormComponent {
|
|
1254
|
+
formService;
|
|
1255
|
+
events;
|
|
1256
|
+
group = null;
|
|
1257
|
+
groupModel = null;
|
|
1258
|
+
model = null;
|
|
1259
|
+
layout = null;
|
|
1260
|
+
labelPrefix = "label";
|
|
1261
|
+
getComponentType = null;
|
|
1262
|
+
blur = new EventEmitter();
|
|
1263
|
+
change = new EventEmitter();
|
|
1264
|
+
focus = new EventEmitter();
|
|
1265
|
+
contentTemplates = null;
|
|
1266
|
+
viewTemplates = null;
|
|
1267
|
+
get status() {
|
|
1268
|
+
return !this.group ? null : this.group.status;
|
|
1269
|
+
}
|
|
1270
|
+
onValueChange = new EventEmitter();
|
|
1271
|
+
onStatusChange = new EventEmitter();
|
|
1272
|
+
onSubmit = new EventEmitter();
|
|
1273
|
+
onDetectChanges = new EventEmitter();
|
|
1274
|
+
subscription = new Subscription();
|
|
1275
|
+
groupSubscription = new Subscription();
|
|
1276
|
+
constructor(formService, events, changeDetectorRef, componentService) {
|
|
1277
|
+
super(changeDetectorRef, componentService);
|
|
1278
|
+
this.formService = formService;
|
|
1279
|
+
this.events = events;
|
|
1280
|
+
this.getComponentType = () => null;
|
|
1281
|
+
}
|
|
1282
|
+
submit() {
|
|
1283
|
+
this.onSubmit.emit(this);
|
|
1284
|
+
}
|
|
1285
|
+
ngOnChanges(changes) {
|
|
1286
|
+
this.groupSubscription.unsubscribe();
|
|
1287
|
+
if (this.group) {
|
|
1288
|
+
this.groupSubscription = ObservableUtils.multiSubscription(this.group.statusChanges.subscribe(() => {
|
|
1289
|
+
this.onStatusChange.emit(this);
|
|
1290
|
+
}), this.group.valueChanges.pipe(debounceTime(500)).subscribe(() => {
|
|
1291
|
+
this.formService.notifyChanges(this.model, this.group);
|
|
1292
|
+
}), this.change.pipe(groupBy(ev => ev.model))
|
|
1293
|
+
.pipe(mergeMap(t => t.pipe(debounceTime(500))))
|
|
1294
|
+
.subscribe(ev => {
|
|
1295
|
+
this.onValueChange.emit({ ...ev, form: this });
|
|
1296
|
+
}));
|
|
1297
|
+
}
|
|
1298
|
+
if (changes.groupModel) {
|
|
1299
|
+
this.model = this.groupModel?.group;
|
|
1300
|
+
}
|
|
1301
|
+
if (changes.model) {
|
|
1302
|
+
this.groupModel = new DynamicFormGroupModel({ id: "root", group: this.model });
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1305
|
+
ngAfterViewInit() {
|
|
1306
|
+
this.subscription = ObservableUtils.multiSubscription(ObservableUtils.subscribe({
|
|
1307
|
+
subjects: [this.contentTemplates.changes, this.viewTemplates.changes],
|
|
1308
|
+
cb: () => {
|
|
1309
|
+
const templates = this.contentTemplates.toArray().concat(this.viewTemplates.toArray());
|
|
1310
|
+
this.templates.reset(templates);
|
|
1311
|
+
}
|
|
1312
|
+
}), this.events.languageChanged.subscribe(() => {
|
|
1313
|
+
this.formService.notifyChanges(this.model, this.group);
|
|
1314
|
+
this.formService.detectChanges(this);
|
|
1315
|
+
}));
|
|
1316
|
+
}
|
|
1317
|
+
ngOnDestroy() {
|
|
1318
|
+
super.ngOnDestroy();
|
|
1319
|
+
this.subscription.unsubscribe();
|
|
1320
|
+
this.groupSubscription.unsubscribe();
|
|
1321
|
+
}
|
|
1322
|
+
detectChanges() {
|
|
1323
|
+
super.detectChanges();
|
|
1324
|
+
this.onDetectChanges.emit(this);
|
|
1325
|
+
}
|
|
1326
|
+
insertFormArrayGroup(index, formArray, formArrayModel) {
|
|
1327
|
+
this.formService.insertFormArrayGroup(index, formArray, formArrayModel);
|
|
1328
|
+
this.detectChanges();
|
|
1329
|
+
}
|
|
1330
|
+
cloneFormArrayGroup(index, formArray, formArrayModel) {
|
|
1331
|
+
this.formService.cloneFormArrayGroup(index, formArray, formArrayModel);
|
|
1332
|
+
this.detectChanges();
|
|
1333
|
+
}
|
|
1334
|
+
removeFormArrayGroup(index, formArray, formArrayModel) {
|
|
1335
|
+
this.formService.removeFormArrayGroup(index, formArray, formArrayModel);
|
|
1336
|
+
this.detectChanges();
|
|
1337
|
+
}
|
|
1338
|
+
moveFormArrayGroup(index, step, formArray, formArrayModel) {
|
|
1339
|
+
this.formService.moveFormArrayGroup(index, step, formArray, formArrayModel);
|
|
1340
|
+
this.detectChanges();
|
|
1341
|
+
}
|
|
1342
|
+
clearFormArray(formArray, formArrayModel) {
|
|
1343
|
+
this.formService.clearFormArray(formArray, formArrayModel);
|
|
1344
|
+
this.detectChanges();
|
|
1345
|
+
}
|
|
1346
|
+
getClass(model) {
|
|
1347
|
+
const parts = collectPathAble(model, p => p.id);
|
|
1348
|
+
if (parts.length == 0)
|
|
1349
|
+
return "";
|
|
1350
|
+
if (model instanceof DynamicFormGroupModel) {
|
|
1351
|
+
return `form-group-${parts.join("-")}`;
|
|
1352
|
+
}
|
|
1353
|
+
return `form-control-${parts.join("-")}`;
|
|
1354
|
+
}
|
|
1355
|
+
validate(showErrors = true) {
|
|
1356
|
+
if (!this.group)
|
|
1357
|
+
return Promise.resolve();
|
|
1358
|
+
return new Promise((resolve, reject) => {
|
|
1359
|
+
this.group.statusChanges.pipe(first(status => status == "VALID" || status == "INVALID")).subscribe(status => {
|
|
1360
|
+
if (showErrors) {
|
|
1361
|
+
this.formService.showErrors(this);
|
|
1362
|
+
}
|
|
1363
|
+
if (status == "VALID") {
|
|
1364
|
+
resolve(null);
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
reject(null);
|
|
1368
|
+
});
|
|
1369
|
+
this.group.updateValueAndValidity();
|
|
1370
|
+
});
|
|
1371
|
+
}
|
|
1372
|
+
async serialize(validate) {
|
|
1373
|
+
if (!this.group)
|
|
1374
|
+
return null;
|
|
1375
|
+
if (validate) {
|
|
1376
|
+
await this.validate();
|
|
1377
|
+
}
|
|
1378
|
+
return await this.formService.serialize(this.model, this.group);
|
|
1379
|
+
}
|
|
1380
|
+
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 });
|
|
1381
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.0.3", type: DynamicBaseFormComponent, isStandalone: false, selector: "dynamic-base-form", inputs: { group: "group", groupModel: "groupModel", model: "model", layout: "layout", 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 });
|
|
1382
|
+
}
|
|
1383
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormComponent, decorators: [{
|
|
1384
|
+
type: Component,
|
|
1385
|
+
args: [{
|
|
1386
|
+
standalone: false,
|
|
1387
|
+
selector: "dynamic-base-form",
|
|
1388
|
+
template: "",
|
|
1389
|
+
changeDetection: ChangeDetectionStrategy.Default
|
|
1390
|
+
}]
|
|
1391
|
+
}], ctorParameters: () => [{ type: DynamicFormService, decorators: [{
|
|
1392
|
+
type: Inject,
|
|
1393
|
+
args: [DynamicFormService]
|
|
1394
|
+
}] }, { type: i2.EventsService, decorators: [{
|
|
1395
|
+
type: Inject,
|
|
1396
|
+
args: [EventsService]
|
|
1397
|
+
}] }, { type: i0.ChangeDetectorRef }, { type: i1.DynamicFormComponentService }], propDecorators: { group: [{
|
|
1398
|
+
type: Input
|
|
1399
|
+
}], groupModel: [{
|
|
1400
|
+
type: Input
|
|
1401
|
+
}], model: [{
|
|
1402
|
+
type: Input
|
|
1403
|
+
}], layout: [{
|
|
1404
|
+
type: Input
|
|
1405
|
+
}], labelPrefix: [{
|
|
1406
|
+
type: Input
|
|
1407
|
+
}], getComponentType: [{
|
|
1408
|
+
type: Input
|
|
1409
|
+
}], blur: [{
|
|
1410
|
+
type: Output
|
|
1411
|
+
}], change: [{
|
|
1412
|
+
type: Output
|
|
1413
|
+
}], focus: [{
|
|
1414
|
+
type: Output
|
|
1415
|
+
}], contentTemplates: [{
|
|
1416
|
+
type: ContentChildren,
|
|
1417
|
+
args: [DynamicTemplateDirective]
|
|
1418
|
+
}], viewTemplates: [{
|
|
1419
|
+
type: ViewChildren,
|
|
1420
|
+
args: [DynamicTemplateDirective]
|
|
1421
|
+
}], onValueChange: [{
|
|
1422
|
+
type: Output
|
|
1423
|
+
}], onStatusChange: [{
|
|
1424
|
+
type: Output
|
|
1425
|
+
}], onSubmit: [{
|
|
1426
|
+
type: Output
|
|
1427
|
+
}], onDetectChanges: [{
|
|
1428
|
+
type: Output
|
|
1429
|
+
}] } });
|
|
1430
|
+
|
|
1431
|
+
class DynamicBaseFormControlContainerComponent extends DynamicFormControlContainerComponent {
|
|
1432
|
+
form;
|
|
1433
|
+
cdr;
|
|
1434
|
+
injector;
|
|
1435
|
+
contentTemplateList = null;
|
|
1436
|
+
klass = null;
|
|
1437
|
+
context = null;
|
|
1438
|
+
group = null;
|
|
1439
|
+
hostClass = null;
|
|
1440
|
+
inputTemplateList = null;
|
|
1441
|
+
layout = null;
|
|
1442
|
+
model = null;
|
|
1443
|
+
blur = new EventEmitter();
|
|
1444
|
+
change = new EventEmitter();
|
|
1445
|
+
focus = new EventEmitter();
|
|
1446
|
+
componentViewContainerRef = null;
|
|
1447
|
+
get componentType() {
|
|
1448
|
+
return this.form.getComponentType?.(this.model, this.injector)
|
|
1449
|
+
?? this.componentService.getCustomComponentType(this.model);
|
|
1450
|
+
}
|
|
1451
|
+
get startTemplate() {
|
|
1452
|
+
return (this.model.type == DYNAMIC_FORM_CONTROL_TYPE_ARRAY)
|
|
1453
|
+
? this.layoutService.getAlignedTemplate(this.model, this.templates, "ARRAY_START")
|
|
1454
|
+
: this.layoutService.getStartTemplate(this.model, this.templates);
|
|
1455
|
+
}
|
|
1456
|
+
get endTemplate() {
|
|
1457
|
+
return (this.model.type == DYNAMIC_FORM_CONTROL_TYPE_ARRAY)
|
|
1458
|
+
? this.layoutService.getAlignedTemplate(this.model, this.templates, "ARRAY_END")
|
|
1459
|
+
: this.layoutService.getEndTemplate(this.model, this.templates);
|
|
1460
|
+
}
|
|
1461
|
+
get formService() {
|
|
1462
|
+
return this.form.formService;
|
|
1463
|
+
}
|
|
1464
|
+
onDetectChanges;
|
|
1465
|
+
constructor(form, cdr, injector, cfr, layoutService, validationService, componentService, relationService) {
|
|
1466
|
+
super(cdr, cfr, layoutService, validationService, componentService, relationService);
|
|
1467
|
+
this.form = form;
|
|
1468
|
+
this.cdr = cdr;
|
|
1469
|
+
this.injector = injector;
|
|
1470
|
+
}
|
|
1471
|
+
ngOnInit() {
|
|
1472
|
+
super.ngOnInit();
|
|
1473
|
+
this.onDetectChanges = this.form.onDetectChanges.subscribe(() => {
|
|
1474
|
+
this.changeDetectorRef.detectChanges();
|
|
1475
|
+
});
|
|
1476
|
+
}
|
|
1477
|
+
ngOnDestroy() {
|
|
1478
|
+
super.ngOnDestroy();
|
|
1479
|
+
this.onDetectChanges.unsubscribe();
|
|
1480
|
+
}
|
|
1481
|
+
getLabel() {
|
|
1482
|
+
const label = collectPathAble(this.model, p => p.label);
|
|
1483
|
+
if (label.length == 0)
|
|
1484
|
+
return "";
|
|
1485
|
+
if (this.form?.labelPrefix) {
|
|
1486
|
+
label.unshift(this.form.labelPrefix);
|
|
1487
|
+
}
|
|
1488
|
+
return label.join(".");
|
|
1489
|
+
}
|
|
1490
|
+
getLabelIcon() {
|
|
1491
|
+
if (this.context instanceof DynamicFormArrayGroupModel) {
|
|
1492
|
+
const arrayModel = this.context.context;
|
|
1493
|
+
if (arrayModel && arrayModel.sortBy == this.model.id) {
|
|
1494
|
+
return arrayModel.sortOrder;
|
|
1495
|
+
}
|
|
1496
|
+
}
|
|
1497
|
+
return null;
|
|
1498
|
+
}
|
|
1499
|
+
clickLabel() {
|
|
1500
|
+
if (this.context instanceof DynamicFormArrayGroupModel) {
|
|
1501
|
+
const arrayModel = this.context.context;
|
|
1502
|
+
if (arrayModel) {
|
|
1503
|
+
arrayModel.sortBy = this.model.id;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
createFormControlComponent() {
|
|
1508
|
+
super.createFormControlComponent();
|
|
1509
|
+
const component = this.componentRef?.instance;
|
|
1510
|
+
if (!component || !ObjectUtils.isFunction(component.initialize))
|
|
1511
|
+
return;
|
|
1512
|
+
component.initialize(this.changeDetectorRef);
|
|
1513
|
+
}
|
|
1514
|
+
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 });
|
|
1515
|
+
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: [
|
|
1516
|
+
{ provide: DynamicFormControlContainerComponent, useExisting: DynamicBaseFormControlContainerComponent }
|
|
1517
|
+
], 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 });
|
|
1518
|
+
}
|
|
1519
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormControlContainerComponent, decorators: [{
|
|
1520
|
+
type: Component,
|
|
1521
|
+
args: [{
|
|
1522
|
+
standalone: false,
|
|
1523
|
+
selector: "dynamic-base-form-control",
|
|
1524
|
+
template: "",
|
|
1525
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
1526
|
+
providers: [
|
|
1527
|
+
{ provide: DynamicFormControlContainerComponent, useExisting: DynamicBaseFormControlContainerComponent }
|
|
1528
|
+
]
|
|
1529
|
+
}]
|
|
1530
|
+
}], 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: [{
|
|
1531
|
+
type: ContentChildren,
|
|
1532
|
+
args: [DynamicTemplateDirective]
|
|
1533
|
+
}], klass: [{
|
|
1534
|
+
type: HostBinding,
|
|
1535
|
+
args: ["class"]
|
|
1536
|
+
}], context: [{
|
|
1537
|
+
type: Input
|
|
1538
|
+
}], group: [{
|
|
1539
|
+
type: Input
|
|
1540
|
+
}], hostClass: [{
|
|
1541
|
+
type: Input
|
|
1542
|
+
}], inputTemplateList: [{
|
|
1543
|
+
type: Input,
|
|
1544
|
+
args: ["templates"]
|
|
1545
|
+
}], layout: [{
|
|
1546
|
+
type: Input
|
|
1547
|
+
}], model: [{
|
|
1548
|
+
type: Input
|
|
1549
|
+
}], blur: [{
|
|
1550
|
+
type: Output
|
|
1551
|
+
}], change: [{
|
|
1552
|
+
type: Output
|
|
1553
|
+
}], focus: [{
|
|
1554
|
+
type: Output
|
|
1555
|
+
}], componentViewContainerRef: [{
|
|
1556
|
+
type: ViewChild,
|
|
1557
|
+
args: ["componentViewContainer", {
|
|
1558
|
+
read: ViewContainerRef,
|
|
1559
|
+
static: true
|
|
1560
|
+
}]
|
|
1561
|
+
}] } });
|
|
1562
|
+
|
|
1563
|
+
class DynamicBaseFormArrayComponent extends DynamicFormArrayComponent {
|
|
1564
|
+
form;
|
|
1565
|
+
injector;
|
|
1566
|
+
cdr;
|
|
1567
|
+
formLayout = null;
|
|
1568
|
+
group = null;
|
|
1569
|
+
layout = null;
|
|
1570
|
+
model = null;
|
|
1571
|
+
templates = null;
|
|
1572
|
+
blur = new EventEmitter();
|
|
1573
|
+
change = new EventEmitter();
|
|
1574
|
+
customEvent = new EventEmitter();
|
|
1575
|
+
focus = new EventEmitter();
|
|
1576
|
+
components = null;
|
|
1577
|
+
get useTabs() {
|
|
1578
|
+
return this.model?.useTabs;
|
|
1579
|
+
}
|
|
1580
|
+
subscription;
|
|
1581
|
+
constructor(layoutService, validationService, form, injector, cdr) {
|
|
1582
|
+
super(layoutService, validationService);
|
|
1583
|
+
this.form = form;
|
|
1584
|
+
this.injector = injector;
|
|
1585
|
+
this.cdr = cdr;
|
|
1586
|
+
}
|
|
1587
|
+
initialize(cdr) {
|
|
1588
|
+
this.subscription = this.model.filteredGroups.subscribe(filteredGroups => {
|
|
1589
|
+
this.updateGroups(filteredGroups);
|
|
1590
|
+
});
|
|
1591
|
+
this.model.initialize(this.array);
|
|
1592
|
+
}
|
|
1593
|
+
ngOnDestroy() {
|
|
1594
|
+
if (this.subscription)
|
|
1595
|
+
this.subscription.unsubscribe();
|
|
1596
|
+
}
|
|
1597
|
+
saveTab(index) {
|
|
1598
|
+
this.model.saveTab(index, this.model.getFiltered(index), this.model, this.injector);
|
|
1599
|
+
}
|
|
1600
|
+
restoreTab() {
|
|
1601
|
+
return this.model.restoreTab(this.model, this.injector);
|
|
1602
|
+
}
|
|
1603
|
+
getTabLabel(index, model) {
|
|
1604
|
+
return this.model.getTabLabel(index, model, this.model, this.array, this.injector);
|
|
1605
|
+
}
|
|
1606
|
+
getClass(context, place, model) {
|
|
1607
|
+
return [
|
|
1608
|
+
context == "element" ? this.getModelClass(model) : null,
|
|
1609
|
+
context == "element" ? this.getAdditionalClass(model) : null,
|
|
1610
|
+
super.getClass(context, place, model),
|
|
1611
|
+
model instanceof DynamicFormValueControlModel ? model.additional?.classes : null
|
|
1612
|
+
].filter(cls => !!cls).join(" ");
|
|
1613
|
+
}
|
|
1614
|
+
getModelClass(model) {
|
|
1615
|
+
const parts = collectPathAble(model, p => p.id);
|
|
1616
|
+
if (parts.length == 0)
|
|
1617
|
+
return "";
|
|
1618
|
+
if (model instanceof DynamicFormGroupModel$1) {
|
|
1619
|
+
return `form-group-${parts.join("-")}`;
|
|
1620
|
+
}
|
|
1621
|
+
return `form-control-${parts.join("-")}`;
|
|
1622
|
+
}
|
|
1623
|
+
getAdditionalClass(model) {
|
|
1624
|
+
if (model instanceof DynamicFormArrayModel) {
|
|
1625
|
+
return model.additional?.classes;
|
|
1626
|
+
}
|
|
1627
|
+
if (model instanceof DynamicFormValueControlModel) {
|
|
1628
|
+
return model.additional?.classes;
|
|
1629
|
+
}
|
|
1630
|
+
return null;
|
|
1631
|
+
}
|
|
1632
|
+
updateGroups(filteredGroups) {
|
|
1633
|
+
this.cdr.detectChanges();
|
|
1634
|
+
this.components.forEach(t => t.cdr.detectChanges());
|
|
1635
|
+
}
|
|
1636
|
+
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 });
|
|
1637
|
+
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 });
|
|
1638
|
+
}
|
|
1639
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormArrayComponent, decorators: [{
|
|
1640
|
+
type: Component,
|
|
1641
|
+
args: [{
|
|
1642
|
+
standalone: false,
|
|
1643
|
+
selector: "dynamic-base-form-array",
|
|
1644
|
+
template: "",
|
|
1645
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
1646
|
+
}]
|
|
1647
|
+
}], ctorParameters: () => [{ type: i1.DynamicFormLayoutService }, { type: i1.DynamicFormValidationService }, { type: DynamicBaseFormComponent }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }], propDecorators: { formLayout: [{
|
|
1648
|
+
type: Input
|
|
1649
|
+
}], group: [{
|
|
1650
|
+
type: Input
|
|
1651
|
+
}], layout: [{
|
|
1652
|
+
type: Input
|
|
1653
|
+
}], model: [{
|
|
1654
|
+
type: Input
|
|
1655
|
+
}], templates: [{
|
|
1656
|
+
type: Input
|
|
1657
|
+
}], blur: [{
|
|
1658
|
+
type: Output
|
|
1659
|
+
}], change: [{
|
|
1660
|
+
type: Output
|
|
1661
|
+
}], customEvent: [{
|
|
1662
|
+
type: Output
|
|
1663
|
+
}], focus: [{
|
|
1664
|
+
type: Output
|
|
1665
|
+
}], components: [{
|
|
1666
|
+
type: ViewChildren,
|
|
1667
|
+
args: [forwardRef(() => DynamicBaseFormControlContainerComponent)]
|
|
1668
|
+
}] } });
|
|
1669
|
+
|
|
1670
|
+
class DynamicBaseFormControlComponent extends DynamicFormControlComponent {
|
|
1671
|
+
form;
|
|
1672
|
+
injector;
|
|
1673
|
+
cdr;
|
|
1674
|
+
formLayout = null;
|
|
1675
|
+
group = null;
|
|
1676
|
+
layout = null;
|
|
1677
|
+
model = null;
|
|
1678
|
+
blur = new EventEmitter();
|
|
1679
|
+
change = new EventEmitter();
|
|
1680
|
+
focus = new EventEmitter();
|
|
1681
|
+
subscription;
|
|
1682
|
+
constructor(layoutService, validationService, form, injector, cdr) {
|
|
1683
|
+
super(layoutService, validationService);
|
|
1684
|
+
this.form = form;
|
|
1685
|
+
this.injector = injector;
|
|
1686
|
+
this.cdr = cdr;
|
|
1687
|
+
}
|
|
1688
|
+
ngAfterViewInit() {
|
|
1689
|
+
this.subscription = this.control.valueChanges.pipe(debounceTime(500)).subscribe(value => {
|
|
1690
|
+
this.onValueChanged(value);
|
|
1691
|
+
});
|
|
1692
|
+
}
|
|
1693
|
+
ngOnDestroy() {
|
|
1694
|
+
if (!this.subscription)
|
|
1695
|
+
return;
|
|
1696
|
+
this.subscription.unsubscribe();
|
|
1697
|
+
}
|
|
1698
|
+
submit() {
|
|
1699
|
+
this.form.submit();
|
|
1700
|
+
}
|
|
1701
|
+
onValueChanged(value) {
|
|
1702
|
+
}
|
|
1703
|
+
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 }, { token: i0.Injector }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
|
|
1704
|
+
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 });
|
|
1705
|
+
}
|
|
1706
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormControlComponent, decorators: [{
|
|
1707
|
+
type: Component,
|
|
1708
|
+
args: [{
|
|
1709
|
+
standalone: false,
|
|
1710
|
+
selector: "dynamic-base-form-control",
|
|
1711
|
+
template: "",
|
|
1712
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
1713
|
+
}]
|
|
1714
|
+
}], ctorParameters: () => [{ type: i1.DynamicFormLayoutService }, { type: i1.DynamicFormValidationService }, { type: DynamicBaseFormComponent }, { type: i0.Injector }, { type: i0.ChangeDetectorRef }], propDecorators: { formLayout: [{
|
|
1715
|
+
type: Input
|
|
1716
|
+
}], group: [{
|
|
1717
|
+
type: Input
|
|
1718
|
+
}], layout: [{
|
|
1719
|
+
type: Input
|
|
1720
|
+
}], model: [{
|
|
1721
|
+
type: Input
|
|
1722
|
+
}], blur: [{
|
|
1723
|
+
type: Output
|
|
1724
|
+
}], change: [{
|
|
1725
|
+
type: Output
|
|
1726
|
+
}], focus: [{
|
|
1727
|
+
type: Output
|
|
1728
|
+
}] } });
|
|
1729
|
+
|
|
1730
|
+
class DynamicBaseFormGroupComponent extends DynamicFormGroupComponent {
|
|
1731
|
+
layoutService;
|
|
1732
|
+
validationService;
|
|
1733
|
+
formLayout = null;
|
|
1734
|
+
group = null;
|
|
1735
|
+
layout = null;
|
|
1736
|
+
model = null;
|
|
1737
|
+
templates = [];
|
|
1738
|
+
blur = new EventEmitter();
|
|
1739
|
+
change = new EventEmitter();
|
|
1740
|
+
customEvent = new EventEmitter();
|
|
1741
|
+
focus = new EventEmitter();
|
|
1742
|
+
components = null;
|
|
1743
|
+
constructor(layoutService, validationService) {
|
|
1744
|
+
super(layoutService, validationService);
|
|
1745
|
+
this.layoutService = layoutService;
|
|
1746
|
+
this.validationService = validationService;
|
|
1747
|
+
}
|
|
1748
|
+
getClass(context, place, model) {
|
|
1749
|
+
return [
|
|
1750
|
+
context == "element" ? this.getModelClass(model) : null,
|
|
1751
|
+
context == "element" ? this.getAdditionalClass(model) : null,
|
|
1752
|
+
super.getClass(context, place, model)
|
|
1753
|
+
].filter(cls => !!cls).join(" ");
|
|
1754
|
+
}
|
|
1755
|
+
getModelClass(model) {
|
|
1756
|
+
const parts = collectPathAble(model, p => p.id);
|
|
1757
|
+
if (parts.length == 0)
|
|
1758
|
+
return "";
|
|
1759
|
+
if (model instanceof DynamicFormGroupModel) {
|
|
1760
|
+
return `form-group-${parts.join("-")}`;
|
|
1761
|
+
}
|
|
1762
|
+
return `form-control-${parts.join("-")}`;
|
|
1763
|
+
}
|
|
1764
|
+
getAdditionalClass(model) {
|
|
1765
|
+
if (model instanceof DynamicFormArrayModel) {
|
|
1766
|
+
return model.additional?.classes;
|
|
1767
|
+
}
|
|
1768
|
+
if (model instanceof DynamicFormValueControlModel) {
|
|
1769
|
+
return model.additional?.classes;
|
|
1770
|
+
}
|
|
1771
|
+
return null;
|
|
1772
|
+
}
|
|
1773
|
+
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 });
|
|
1774
|
+
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 });
|
|
1775
|
+
}
|
|
1776
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseFormGroupComponent, decorators: [{
|
|
1777
|
+
type: Component,
|
|
1778
|
+
args: [{
|
|
1779
|
+
standalone: false,
|
|
1780
|
+
selector: "dynamic-base-form-group",
|
|
1781
|
+
template: "",
|
|
1782
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
1783
|
+
}]
|
|
1784
|
+
}], ctorParameters: () => [{ type: i1.DynamicFormLayoutService }, { type: i1.DynamicFormValidationService }], propDecorators: { formLayout: [{
|
|
1785
|
+
type: Input
|
|
1786
|
+
}], group: [{
|
|
1787
|
+
type: Input
|
|
1788
|
+
}], layout: [{
|
|
1789
|
+
type: Input
|
|
1790
|
+
}], model: [{
|
|
1791
|
+
type: Input
|
|
1792
|
+
}], templates: [{
|
|
1793
|
+
type: Input
|
|
1794
|
+
}], blur: [{
|
|
1795
|
+
type: Output
|
|
1796
|
+
}], change: [{
|
|
1797
|
+
type: Output
|
|
1798
|
+
}], customEvent: [{
|
|
1799
|
+
type: Output
|
|
1800
|
+
}], focus: [{
|
|
1801
|
+
type: Output
|
|
1802
|
+
}], components: [{
|
|
1803
|
+
type: ViewChildren,
|
|
1804
|
+
args: [forwardRef(() => DynamicFormControlContainerComponent)]
|
|
1805
|
+
}] } });
|
|
1806
|
+
|
|
1807
|
+
class DynamicBaseSelectComponent extends DynamicBaseFormControlComponent {
|
|
1808
|
+
groups$;
|
|
1809
|
+
hasOptions;
|
|
1810
|
+
ngOnInit() {
|
|
1811
|
+
this.groups$ = new BehaviorSubject([]);
|
|
1812
|
+
this.subscription = this.model.options$.subscribe(options => {
|
|
1813
|
+
const groupBy = this.model.inline || !this.model.multiple ? this.model.groupBy : null;
|
|
1814
|
+
const grouped = options.reduce((res, option) => {
|
|
1815
|
+
const key = replaceSpecialChars(groupBy ? option.props[this.model.groupBy] || "default" : "default", "-");
|
|
1816
|
+
res[key] = res[key] || [];
|
|
1817
|
+
res[key].push(option);
|
|
1818
|
+
return res;
|
|
1819
|
+
}, {});
|
|
1820
|
+
const groups = Object.keys(grouped).map(group => {
|
|
1821
|
+
return {
|
|
1822
|
+
group,
|
|
1823
|
+
options: grouped[group]
|
|
1824
|
+
};
|
|
1825
|
+
});
|
|
1826
|
+
this.hasOptions = groups.length > 0;
|
|
1827
|
+
this.groups$.next(groups);
|
|
1828
|
+
this.cdr.detectChanges();
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
ngOnDestroy() {
|
|
1832
|
+
if (this.subscription)
|
|
1833
|
+
this.subscription.unsubscribe();
|
|
1834
|
+
}
|
|
1835
|
+
isSelected(option) {
|
|
1836
|
+
if (this.model.multiple) {
|
|
1837
|
+
return this.control.value?.indexOf(option.value) >= 0;
|
|
1838
|
+
}
|
|
1839
|
+
return this.control.value == option.value;
|
|
1840
|
+
}
|
|
1841
|
+
selectToggle(option, state) {
|
|
1842
|
+
if (this.model.multiple) {
|
|
1843
|
+
const value = Array.from(this.control.value || []);
|
|
1844
|
+
const index = value.indexOf(option.value);
|
|
1845
|
+
if (index >= 0) {
|
|
1846
|
+
value.splice(index, 1);
|
|
1847
|
+
}
|
|
1848
|
+
if (state) {
|
|
1849
|
+
value.push(option.value);
|
|
1850
|
+
}
|
|
1851
|
+
this.control.setValue(value);
|
|
1852
|
+
this.onChange(value);
|
|
1853
|
+
return;
|
|
1854
|
+
}
|
|
1855
|
+
this.control.setValue(option.value);
|
|
1856
|
+
this.onChange(option.value);
|
|
1857
|
+
}
|
|
1858
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component });
|
|
1859
|
+
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 });
|
|
1860
|
+
}
|
|
1861
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: DynamicBaseSelectComponent, decorators: [{
|
|
1862
|
+
type: Component,
|
|
1863
|
+
args: [{
|
|
1864
|
+
standalone: false,
|
|
1865
|
+
selector: "dynamic-base-select",
|
|
1866
|
+
template: "",
|
|
1867
|
+
changeDetection: ChangeDetectionStrategy.OnPush
|
|
1868
|
+
}]
|
|
1869
|
+
}] });
|
|
1870
|
+
|
|
1871
|
+
// --- Components ---
|
|
1872
|
+
const components = [
|
|
1873
|
+
DynamicBaseFormComponent,
|
|
1874
|
+
DynamicBaseFormArrayComponent,
|
|
1875
|
+
DynamicBaseFormControlComponent,
|
|
1876
|
+
DynamicBaseFormControlContainerComponent,
|
|
1877
|
+
DynamicBaseFormGroupComponent,
|
|
1878
|
+
DynamicBaseSelectComponent
|
|
1879
|
+
];
|
|
1880
|
+
// --- Directives ---
|
|
1881
|
+
const directives = [
|
|
1882
|
+
AsyncSubmitDirective,
|
|
1883
|
+
];
|
|
1884
|
+
// --- Pipes ---
|
|
1885
|
+
const pipes = [];
|
|
1886
|
+
function defaultFormControlProvider() {
|
|
1887
|
+
return () => null;
|
|
1888
|
+
}
|
|
1889
|
+
|
|
1890
|
+
class NgxDynamicFormModule {
|
|
1891
|
+
static forRoot(config) {
|
|
1892
|
+
return {
|
|
1893
|
+
ngModule: NgxDynamicFormModule,
|
|
1894
|
+
providers: [
|
|
1895
|
+
DynamicFormService,
|
|
1896
|
+
{
|
|
1897
|
+
provide: DynamicFormService$1,
|
|
1898
|
+
useExisting: DynamicFormService
|
|
1899
|
+
},
|
|
1900
|
+
{
|
|
1901
|
+
provide: DYNAMIC_FORM_CONTROL_MAP_FN,
|
|
1902
|
+
useFactory: (config?.controlProvider || defaultFormControlProvider),
|
|
1903
|
+
deps: [Injector]
|
|
1904
|
+
}
|
|
1905
|
+
]
|
|
1906
|
+
};
|
|
1907
|
+
}
|
|
1908
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgxDynamicFormModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
|
|
1909
|
+
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,
|
|
1910
|
+
FormsModule,
|
|
1911
|
+
ReactiveFormsModule,
|
|
1912
|
+
NgxUtilsModule], exports: [DynamicBaseFormComponent, DynamicBaseFormArrayComponent, DynamicBaseFormControlComponent, DynamicBaseFormControlContainerComponent, DynamicBaseFormGroupComponent, DynamicBaseSelectComponent, AsyncSubmitDirective, FormsModule,
|
|
1913
|
+
ReactiveFormsModule,
|
|
1914
|
+
NgxUtilsModule] });
|
|
1915
|
+
static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgxDynamicFormModule, providers: [
|
|
1916
|
+
...pipes,
|
|
1917
|
+
{ provide: NG_VALIDATORS, useValue: validateJSON, multi: true },
|
|
1918
|
+
{ provide: NG_VALIDATORS, useValue: validateRequiredTranslation, multi: true },
|
|
1919
|
+
{ provide: NG_VALIDATORS, useValue: validateItemsMinLength, multi: true },
|
|
1920
|
+
{ provide: NG_VALIDATORS, useValue: validateItemsMaxLength, multi: true },
|
|
1921
|
+
{ provide: NG_VALIDATORS, useValue: validateItemsMinValue, multi: true },
|
|
1922
|
+
{ provide: NG_VALIDATORS, useValue: validateItemsMaxValue, multi: true },
|
|
1923
|
+
{
|
|
1924
|
+
provide: DYNAMIC_VALIDATORS,
|
|
1925
|
+
useValue: new Map([
|
|
1926
|
+
["json", validateJSON],
|
|
1927
|
+
["requiredTranslation", validateRequiredTranslation],
|
|
1928
|
+
["phone", validatePhone],
|
|
1929
|
+
["itemsMinLength", validateItemsMinLength],
|
|
1930
|
+
["itemsMaxLength", validateItemsMaxLength],
|
|
1931
|
+
["itemsMinValue", validateItemsMinValue],
|
|
1932
|
+
["itemsMaxValue", validateItemsMaxValue],
|
|
1933
|
+
])
|
|
1934
|
+
}
|
|
1935
|
+
], imports: [CommonModule,
|
|
1936
|
+
FormsModule,
|
|
1937
|
+
ReactiveFormsModule,
|
|
1938
|
+
NgxUtilsModule, FormsModule,
|
|
1939
|
+
ReactiveFormsModule,
|
|
1940
|
+
NgxUtilsModule] });
|
|
1941
|
+
}
|
|
1942
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.3", ngImport: i0, type: NgxDynamicFormModule, decorators: [{
|
|
1943
|
+
type: NgModule,
|
|
1944
|
+
args: [{
|
|
1945
|
+
declarations: [
|
|
1946
|
+
...components,
|
|
1947
|
+
...directives,
|
|
1948
|
+
...pipes
|
|
1949
|
+
],
|
|
1950
|
+
imports: [
|
|
1951
|
+
CommonModule,
|
|
1952
|
+
FormsModule,
|
|
1953
|
+
ReactiveFormsModule,
|
|
1954
|
+
NgxUtilsModule
|
|
1955
|
+
],
|
|
1956
|
+
exports: [
|
|
1957
|
+
...components,
|
|
1958
|
+
...directives,
|
|
1959
|
+
...pipes,
|
|
1960
|
+
FormsModule,
|
|
1961
|
+
ReactiveFormsModule,
|
|
1962
|
+
NgxUtilsModule
|
|
1963
|
+
],
|
|
1964
|
+
providers: [
|
|
1965
|
+
...pipes,
|
|
1966
|
+
{ provide: NG_VALIDATORS, useValue: validateJSON, multi: true },
|
|
1967
|
+
{ provide: NG_VALIDATORS, useValue: validateRequiredTranslation, multi: true },
|
|
1968
|
+
{ provide: NG_VALIDATORS, useValue: validateItemsMinLength, multi: true },
|
|
1969
|
+
{ provide: NG_VALIDATORS, useValue: validateItemsMaxLength, multi: true },
|
|
1970
|
+
{ provide: NG_VALIDATORS, useValue: validateItemsMinValue, multi: true },
|
|
1971
|
+
{ provide: NG_VALIDATORS, useValue: validateItemsMaxValue, multi: true },
|
|
1972
|
+
{
|
|
1973
|
+
provide: DYNAMIC_VALIDATORS,
|
|
1974
|
+
useValue: new Map([
|
|
1975
|
+
["json", validateJSON],
|
|
1976
|
+
["requiredTranslation", validateRequiredTranslation],
|
|
1977
|
+
["phone", validatePhone],
|
|
1978
|
+
["itemsMinLength", validateItemsMinLength],
|
|
1979
|
+
["itemsMaxLength", validateItemsMaxLength],
|
|
1980
|
+
["itemsMinValue", validateItemsMinValue],
|
|
1981
|
+
["itemsMaxValue", validateItemsMaxValue],
|
|
1982
|
+
])
|
|
1983
|
+
}
|
|
1984
|
+
]
|
|
1985
|
+
}]
|
|
1986
|
+
}] });
|
|
1987
|
+
|
|
1988
|
+
/**
|
|
1989
|
+
* Generated bundle index. Do not edit.
|
|
1990
|
+
*/
|
|
1991
|
+
|
|
1992
|
+
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 };
|
|
1993
|
+
//# sourceMappingURL=stemy-ngx-dynamic-form.mjs.map
|