@stemy/ngx-dynamic-form 10.2.24 → 12.0.0
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/bundles/stemy-ngx-dynamic-form.umd.js +1781 -901
- package/bundles/stemy-ngx-dynamic-form.umd.js.map +1 -1
- package/esm2015/ngx-dynamic-form/common-types.js +463 -7
- package/esm2015/ngx-dynamic-form/components/base/dynamic-form-base.component.js +87 -0
- package/esm2015/ngx-dynamic-form/components/dynamic-form/dynamic-form.component.js +91 -0
- package/esm2015/ngx-dynamic-form/components/dynamic-form-file/dynamic-form-file.component.js +112 -0
- package/esm2015/ngx-dynamic-form/components/dynamic-form-group/dynamic-form-group.component.js +19 -0
- package/esm2015/ngx-dynamic-form/components/dynamic-form-input/dynamic-form-input.component.js +69 -0
- package/esm2015/ngx-dynamic-form/components/dynamic-form-model/dynamic-form-model.component.js +23 -0
- package/esm2015/ngx-dynamic-form/components/dynamic-form-select/dynamic-form-select.component.js +73 -0
- package/esm2015/ngx-dynamic-form/components/dynamic-form-static/dynamic-form-static.component.js +20 -0
- package/esm2015/ngx-dynamic-form/components/dynamic-forms/dynamic-forms.component.js +134 -0
- package/esm2015/ngx-dynamic-form/directives/async-submit.directive.js +6 -17
- package/esm2015/ngx-dynamic-form/directives/dynamic-form-control.directive.js +32 -0
- package/esm2015/ngx-dynamic-form/directives/dynamic-form-group.directive.js +40 -0
- package/esm2015/ngx-dynamic-form/directives/dynamic-form-template.directive.js +38 -0
- package/esm2015/ngx-dynamic-form/ngx-dynamic-form.module.js +36 -35
- package/esm2015/ngx-dynamic-form/services/dynamic-form.service.js +41 -385
- package/esm2015/ngx-dynamic-form/services/form-utilities.js +108 -0
- package/esm2015/ngx-dynamic-form/services/open-api.service.js +130 -0
- package/esm2015/public_api.js +15 -6
- package/esm2015/stemy-ngx-dynamic-form.js +4 -3
- package/fesm2015/stemy-ngx-dynamic-form.js +1357 -593
- package/fesm2015/stemy-ngx-dynamic-form.js.map +1 -1
- package/ngx-dynamic-form/common-types.d.ts +181 -27
- package/ngx-dynamic-form/components/base/dynamic-form-base.component.d.ts +44 -0
- package/ngx-dynamic-form/components/dynamic-form/dynamic-form.component.d.ts +21 -0
- package/ngx-dynamic-form/components/dynamic-form-file/dynamic-form-file.component.d.ts +16 -0
- package/ngx-dynamic-form/components/dynamic-form-group/dynamic-form-group.component.d.ts +6 -0
- package/ngx-dynamic-form/components/dynamic-form-input/dynamic-form-input.component.d.ts +12 -0
- package/ngx-dynamic-form/components/dynamic-form-model/dynamic-form-model.component.d.ts +6 -0
- package/ngx-dynamic-form/components/dynamic-form-select/dynamic-form-select.component.d.ts +9 -0
- package/ngx-dynamic-form/components/dynamic-form-static/dynamic-form-static.component.d.ts +5 -0
- package/ngx-dynamic-form/components/dynamic-forms/dynamic-forms.component.d.ts +26 -0
- package/ngx-dynamic-form/directives/async-submit.directive.d.ts +1 -5
- package/ngx-dynamic-form/directives/dynamic-form-control.directive.d.ts +12 -0
- package/ngx-dynamic-form/directives/dynamic-form-group.directive.d.ts +14 -0
- package/ngx-dynamic-form/directives/dynamic-form-template.directive.d.ts +16 -0
- package/ngx-dynamic-form/ngx-dynamic-form.module.d.ts +15 -5
- package/ngx-dynamic-form/services/dynamic-form.service.d.ts +11 -39
- package/ngx-dynamic-form/services/form-utilities.d.ts +19 -0
- package/ngx-dynamic-form/services/open-api.service.d.ts +37 -0
- package/package.json +16 -17
- package/public_api.d.ts +14 -5
- package/stemy-ngx-dynamic-form.d.ts +3 -2
- package/stemy-ngx-dynamic-form.metadata.json +1 -1
- package/bundles/stemy-ngx-dynamic-form.umd.min.js +0 -16
- package/bundles/stemy-ngx-dynamic-form.umd.min.js.map +0 -1
- package/esm2015/ngx-dynamic-form/components/base/dynamic-base-form-control-container.component.js +0 -91
- package/esm2015/ngx-dynamic-form/components/base/dynamic-base-form.component.js +0 -129
- package/esm2015/ngx-dynamic-form/services/dynamic-form-validation.service.js +0 -11
- package/esm2015/ngx-dynamic-form/utils/dynamic-form-array.model.js +0 -8
- package/esm2015/ngx-dynamic-form/utils/form-subject.js +0 -18
- package/esm2015/ngx-dynamic-form/utils/validators.js +0 -28
- package/ngx-dynamic-form/components/base/dynamic-base-form-control-container.component.d.ts +0 -37
- package/ngx-dynamic-form/components/base/dynamic-base-form.component.d.ts +0 -37
- package/ngx-dynamic-form/services/dynamic-form-validation.service.d.ts +0 -5
- package/ngx-dynamic-form/utils/dynamic-form-array.model.d.ts +0 -12
- package/ngx-dynamic-form/utils/form-subject.d.ts +0 -8
- package/ngx-dynamic-form/utils/validators.d.ts +0 -4
|
@@ -1,12 +1,447 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { DynamicFormArrayModel as DynamicFormArrayModel$1, DynamicFormService as DynamicFormService$1, DynamicSelectModel, DynamicFormGroupModel, DynamicInputModel, DynamicFileUploadModel, DynamicCheckboxModel, DynamicTextAreaModel, DynamicFormComponentService, DynamicFormValidationService as DynamicFormValidationService$1, DynamicFormComponent, DynamicTemplateDirective, DynamicFormControlContainerComponent, DYNAMIC_FORM_CONTROL_TYPE_ARRAY, DynamicFormLayoutService, DynamicFormRelationService, DYNAMIC_VALIDATORS } from '@ng-dynamic-forms/core';
|
|
1
|
+
import { InjectionToken, Directive, HostBinding, Injectable, Inject, Type, ComponentFactoryResolver, Injector, EventEmitter, ChangeDetectorRef, ElementRef, Renderer2, Input, Output, HostListener, ViewContainerRef, TemplateRef, ContentChild, ContentChildren, Component, ViewChildren, ViewChild, NgModule } from '@angular/core';
|
|
2
|
+
import { FormGroup, FormControl, FormsModule, ReactiveFormsModule } from '@angular/forms';
|
|
3
|
+
import { ObjectUtils, ReflectUtils, UniqueUtils, TimerUtils, FileUtils, FactoryDependencies, StringUtils, ApiService, TOASTER_SERVICE, ArrayUtils, LANGUAGE_SERVICE, NgxUtilsModule } from '@stemy/ngx-utils';
|
|
4
|
+
import { __decorate } from 'tslib';
|
|
5
|
+
import { DatePipe, CommonModule } from '@angular/common';
|
|
7
6
|
import { first } from 'rxjs/operators';
|
|
8
|
-
import { CommonModule } from '@angular/common';
|
|
9
7
|
|
|
8
|
+
const FORM_GROUP_TYPE = new InjectionToken("form-group-provider");
|
|
9
|
+
const FORM_CONTROL_PROVIDER = new InjectionToken("form-control-provider");
|
|
10
|
+
class FormControlComponent {
|
|
11
|
+
get form() {
|
|
12
|
+
return !this.control ? null : this.control.form;
|
|
13
|
+
}
|
|
14
|
+
get data() {
|
|
15
|
+
return (!this.control ? {} : this.control.data);
|
|
16
|
+
}
|
|
17
|
+
get value() {
|
|
18
|
+
return !this.control ? null : this.control.value;
|
|
19
|
+
}
|
|
20
|
+
get meta() {
|
|
21
|
+
return !this.control ? null : this.control.meta;
|
|
22
|
+
}
|
|
23
|
+
get inputClass() {
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
FormControlComponent.decorators = [
|
|
28
|
+
{ type: Directive }
|
|
29
|
+
];
|
|
30
|
+
FormControlComponent.propDecorators = {
|
|
31
|
+
inputClass: [{ type: HostBinding, args: ["class.form-input",] }]
|
|
32
|
+
};
|
|
33
|
+
function createValidator(control) {
|
|
34
|
+
const data = control.data || {};
|
|
35
|
+
const validators = [data.validator].concat(data.validators || []).filter(ObjectUtils.isDefined).map(v => {
|
|
36
|
+
return ReflectUtils.resolve(v, control.injector);
|
|
37
|
+
});
|
|
38
|
+
return (ctrl) => new Promise((resolve) => {
|
|
39
|
+
const control = ctrl;
|
|
40
|
+
control.shouldValidate().then(should => {
|
|
41
|
+
if (!should) {
|
|
42
|
+
resolve(null);
|
|
43
|
+
return;
|
|
44
|
+
}
|
|
45
|
+
const validate = validators.map(v => v(control));
|
|
46
|
+
const metaValidator = control.meta.validator;
|
|
47
|
+
if (ObjectUtils.isFunction(metaValidator)) {
|
|
48
|
+
validate.push(metaValidator(control));
|
|
49
|
+
}
|
|
50
|
+
Promise.all(validate).then(results => {
|
|
51
|
+
results = results.filter(error => ObjectUtils.isObject(error) || ObjectUtils.isString(error));
|
|
52
|
+
let result = null;
|
|
53
|
+
if (results.length > 0) {
|
|
54
|
+
result = {};
|
|
55
|
+
results.forEach(error => {
|
|
56
|
+
if (ObjectUtils.isString(error)) {
|
|
57
|
+
result[error] = {};
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
result = Object.assign(result, error);
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
resolve(result);
|
|
64
|
+
});
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
class DynamicFormControlHelper {
|
|
69
|
+
constructor(form, control = null) {
|
|
70
|
+
this.form = form;
|
|
71
|
+
this.control = control;
|
|
72
|
+
this.formId = UniqueUtils.uuid();
|
|
73
|
+
this.meta = {};
|
|
74
|
+
this.hidden = false;
|
|
75
|
+
this.dummyData = {};
|
|
76
|
+
this.readonlyTester = this.createTester("readonly");
|
|
77
|
+
this.hideTester = this.createTester("hidden");
|
|
78
|
+
this.serializeTester = this.createTester("shouldSerialize", (control) => {
|
|
79
|
+
return Promise.resolve(control.visible);
|
|
80
|
+
});
|
|
81
|
+
this.validateTester = this.createTester("shouldValidate", (control) => {
|
|
82
|
+
return Promise.resolve(control.visible);
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
get id() {
|
|
86
|
+
return !this.control ? null : this.control.id;
|
|
87
|
+
}
|
|
88
|
+
get type() {
|
|
89
|
+
return !this.control ? "" : this.control.type;
|
|
90
|
+
}
|
|
91
|
+
get data() {
|
|
92
|
+
return !this.control ? this.dummyData : this.control.data || this.dummyData;
|
|
93
|
+
}
|
|
94
|
+
get visible() {
|
|
95
|
+
return !this.hidden;
|
|
96
|
+
}
|
|
97
|
+
get provider() {
|
|
98
|
+
return this.ctrlProvider;
|
|
99
|
+
}
|
|
100
|
+
load(control) {
|
|
101
|
+
return !this.ctrlProvider ? Promise.resolve(null) : this.ctrlProvider.loader(control);
|
|
102
|
+
}
|
|
103
|
+
check(control) {
|
|
104
|
+
return new Promise(resolve => {
|
|
105
|
+
this.hideTester(control).then(hide => {
|
|
106
|
+
this.hidden = hide;
|
|
107
|
+
this.readonlyTester(control).then(readonly => {
|
|
108
|
+
resolve(control.form.readonly || readonly);
|
|
109
|
+
});
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
shouldSerialize(control) {
|
|
114
|
+
return this.serializeTester(control);
|
|
115
|
+
}
|
|
116
|
+
shouldValidate(control) {
|
|
117
|
+
return this.validateTester(control);
|
|
118
|
+
}
|
|
119
|
+
findProvider(control) {
|
|
120
|
+
this.ctrlProvider = !this.control || !this.control.type ? null : this.form.findProvider(control);
|
|
121
|
+
}
|
|
122
|
+
createTester(test, defaultFunc = null) {
|
|
123
|
+
const tester = this.data[test]
|
|
124
|
+
? ReflectUtils.resolve(this.data[test], this.form.injector)
|
|
125
|
+
: (defaultFunc || (() => Promise.resolve(false)));
|
|
126
|
+
return (control) => tester(control);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
class DynamicFormGroup extends FormGroup {
|
|
130
|
+
constructor(form, control = null) {
|
|
131
|
+
super({}, { updateOn: ((!control || !control.data) ? null : control.data.updateOn) || form.updateOn || "blur" });
|
|
132
|
+
this.form = form;
|
|
133
|
+
this.mName = "";
|
|
134
|
+
this.mModel = {};
|
|
135
|
+
this.mControls = [];
|
|
136
|
+
this.mSerializers = [];
|
|
137
|
+
this.mFieldSets = {};
|
|
138
|
+
this.helper = new DynamicFormControlHelper(form, control);
|
|
139
|
+
this.helper.findProvider(this);
|
|
140
|
+
this.initialized = false;
|
|
141
|
+
this.loading = false;
|
|
142
|
+
this.changeTimer = TimerUtils.createTimeout();
|
|
143
|
+
this.statusChanges.subscribe(() => {
|
|
144
|
+
const root = this.form.root;
|
|
145
|
+
root.onStatusChange.emit(root);
|
|
146
|
+
});
|
|
147
|
+
this.setAsyncValidators(createValidator(this));
|
|
148
|
+
}
|
|
149
|
+
get id() {
|
|
150
|
+
return this.helper.id;
|
|
151
|
+
}
|
|
152
|
+
get type() {
|
|
153
|
+
return this.helper.type;
|
|
154
|
+
}
|
|
155
|
+
get data() {
|
|
156
|
+
return this.helper.data;
|
|
157
|
+
}
|
|
158
|
+
get visible() {
|
|
159
|
+
return this.helper.visible;
|
|
160
|
+
}
|
|
161
|
+
get meta() {
|
|
162
|
+
return this.helper.meta;
|
|
163
|
+
}
|
|
164
|
+
get injector() {
|
|
165
|
+
return this.form.injector;
|
|
166
|
+
}
|
|
167
|
+
get label() {
|
|
168
|
+
return this.data.label !== "" ? `${this.prefix}${this.data.label}` : "";
|
|
169
|
+
}
|
|
170
|
+
get provider() {
|
|
171
|
+
return this.helper.provider;
|
|
172
|
+
}
|
|
173
|
+
get model() {
|
|
174
|
+
return this.mModel;
|
|
175
|
+
}
|
|
176
|
+
get formId() {
|
|
177
|
+
return this.helper.formId;
|
|
178
|
+
}
|
|
179
|
+
get formControls() {
|
|
180
|
+
return this.mControls || [];
|
|
181
|
+
}
|
|
182
|
+
get formFields() {
|
|
183
|
+
return this.mFieldSets || {};
|
|
184
|
+
}
|
|
185
|
+
get prefix() {
|
|
186
|
+
return !this.name ? "" : `${this.name}.`;
|
|
187
|
+
}
|
|
188
|
+
get name() {
|
|
189
|
+
return this.mName;
|
|
190
|
+
}
|
|
191
|
+
get state() {
|
|
192
|
+
return (this.loading ? "LOADING" : this.status);
|
|
193
|
+
}
|
|
194
|
+
static createFormControls(group, controls) {
|
|
195
|
+
if (!controls && ObjectUtils.isObject(group.model)) {
|
|
196
|
+
const props = Object.keys(group.model);
|
|
197
|
+
controls = props.map(id => {
|
|
198
|
+
return getFormControl(group.model, id);
|
|
199
|
+
}).filter(ObjectUtils.isDefined);
|
|
200
|
+
}
|
|
201
|
+
if (!controls)
|
|
202
|
+
return [];
|
|
203
|
+
return controls.map(ctrl => {
|
|
204
|
+
if (ctrl.type == "model") {
|
|
205
|
+
const subGroup = new DynamicFormGroup(group.form, ctrl);
|
|
206
|
+
const model = group.model[ctrl.id] || {};
|
|
207
|
+
const data = subGroup.getData();
|
|
208
|
+
data.name = data.name || group.name;
|
|
209
|
+
subGroup.setup(model, data);
|
|
210
|
+
group.model[ctrl.id] = model;
|
|
211
|
+
group.addControl(subGroup.id, subGroup);
|
|
212
|
+
return subGroup;
|
|
213
|
+
}
|
|
214
|
+
return new DynamicFormControl(ctrl, group);
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
static createFormSerializers(group, serializers) {
|
|
218
|
+
if (!serializers && ObjectUtils.isObject(group.model)) {
|
|
219
|
+
const props = Object.keys(group.model);
|
|
220
|
+
serializers = props.reduce((result, id) => {
|
|
221
|
+
const serializer = getFormSerializer(group.model, id);
|
|
222
|
+
if (!serializer)
|
|
223
|
+
return result;
|
|
224
|
+
result[id] = serializer;
|
|
225
|
+
return result;
|
|
226
|
+
}, {});
|
|
227
|
+
}
|
|
228
|
+
if (!serializers)
|
|
229
|
+
return [];
|
|
230
|
+
return Object.keys(serializers).map(id => {
|
|
231
|
+
const serializer = serializers[id] || defaultSerializer;
|
|
232
|
+
return !serializer ? null : {
|
|
233
|
+
id: id,
|
|
234
|
+
func: ReflectUtils.resolve(serializer, group.injector)
|
|
235
|
+
};
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
getData() {
|
|
239
|
+
return this.data;
|
|
240
|
+
}
|
|
241
|
+
getControl(id) {
|
|
242
|
+
return this.get(id);
|
|
243
|
+
}
|
|
244
|
+
load() {
|
|
245
|
+
const promises = this.mControls.map(c => c.load());
|
|
246
|
+
promises.push(this.helper.load(this));
|
|
247
|
+
return Promise.all(promises);
|
|
248
|
+
}
|
|
249
|
+
check() {
|
|
250
|
+
return new Promise(resolve => {
|
|
251
|
+
this.helper.check(this).then(readonly => {
|
|
252
|
+
if (readonly)
|
|
253
|
+
this.disable({ emitEvent: false });
|
|
254
|
+
else
|
|
255
|
+
this.enable({ emitEvent: false });
|
|
256
|
+
const promises = this.mControls.map(c => c.check());
|
|
257
|
+
Promise.all(promises).then(resolve);
|
|
258
|
+
});
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
shouldSerialize() {
|
|
262
|
+
return this.helper.shouldSerialize(this);
|
|
263
|
+
}
|
|
264
|
+
shouldValidate() {
|
|
265
|
+
return this.helper.shouldValidate(this);
|
|
266
|
+
}
|
|
267
|
+
serialize() {
|
|
268
|
+
return new Promise((resolve) => {
|
|
269
|
+
const result = {};
|
|
270
|
+
const serializers = this.mSerializers.map(s => {
|
|
271
|
+
return new Promise(resolve => {
|
|
272
|
+
s.func(s.id, this).then(res => {
|
|
273
|
+
const ctrl = this.getControl(s.id);
|
|
274
|
+
const promise = !ctrl ? Promise.resolve(true) : ctrl.shouldSerialize();
|
|
275
|
+
promise.then(should => {
|
|
276
|
+
if (should)
|
|
277
|
+
result[s.id] = res;
|
|
278
|
+
resolve(null);
|
|
279
|
+
});
|
|
280
|
+
});
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
Promise.all(serializers).then(() => resolve(result));
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
onFocus() {
|
|
287
|
+
this.markAsUntouched({ onlySelf: true });
|
|
288
|
+
}
|
|
289
|
+
onBlur() {
|
|
290
|
+
this.markAsTouched({ onlySelf: true });
|
|
291
|
+
}
|
|
292
|
+
showErrors() {
|
|
293
|
+
this.markAsTouched({ onlySelf: true });
|
|
294
|
+
this.mControls.forEach(ctrl => ctrl.showErrors());
|
|
295
|
+
}
|
|
296
|
+
reloadControls() {
|
|
297
|
+
let callback = () => { };
|
|
298
|
+
if (this.initialized === false) {
|
|
299
|
+
this.initialized = true;
|
|
300
|
+
this.loading = true;
|
|
301
|
+
callback = () => {
|
|
302
|
+
this.loading = false;
|
|
303
|
+
// this.cdr.detectChanges();
|
|
304
|
+
const root = this.form.root;
|
|
305
|
+
root.onInit.emit(root);
|
|
306
|
+
root.onStatusChange.emit(root);
|
|
307
|
+
// https://github.com/angular/angular/issues/14542
|
|
308
|
+
const statusTimer = TimerUtils.createInterval();
|
|
309
|
+
statusTimer.set(() => {
|
|
310
|
+
if (this.status == "PENDING")
|
|
311
|
+
return;
|
|
312
|
+
statusTimer.clear();
|
|
313
|
+
root.onStatusChange.emit(root);
|
|
314
|
+
}, 50);
|
|
315
|
+
setTimeout(statusTimer.clear, 5000);
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
const promise = new Promise(resolve => {
|
|
319
|
+
this.load().then(() => this.check().then(resolve));
|
|
320
|
+
});
|
|
321
|
+
promise.then(callback, callback);
|
|
322
|
+
return promise;
|
|
323
|
+
}
|
|
324
|
+
setup(model, info) {
|
|
325
|
+
this.mName = info.name || "";
|
|
326
|
+
this.mModel = model;
|
|
327
|
+
this.mControls.forEach(ctrl => this.removeControl(ctrl.id));
|
|
328
|
+
this.mControls = DynamicFormGroup.createFormControls(this, info.controls);
|
|
329
|
+
this.mControls.forEach((ctrl) => this.addControl(ctrl.id, ctrl));
|
|
330
|
+
this.mSerializers = DynamicFormGroup.createFormSerializers(this, info.serializers);
|
|
331
|
+
this.mFieldSets = info.fieldSets ? info.fieldSets.reduce((result, fs) => {
|
|
332
|
+
result[fs.id] = fs;
|
|
333
|
+
return result;
|
|
334
|
+
}, {}) : getFormFieldSets(Object.getPrototypeOf(model).constructor);
|
|
335
|
+
}
|
|
336
|
+
updateModel(control) {
|
|
337
|
+
this.model[control.id] = control.value;
|
|
338
|
+
this.changeTimer.clear();
|
|
339
|
+
this.changeTimer.set(() => {
|
|
340
|
+
this.check().then(() => this.reloadControlsFrom(control, new Set()).then(() => {
|
|
341
|
+
this.form.root.onChange.emit(control);
|
|
342
|
+
}));
|
|
343
|
+
}, 250);
|
|
344
|
+
}
|
|
345
|
+
reloadControlsFrom(control, controls) {
|
|
346
|
+
const data = control.data;
|
|
347
|
+
if (!data || !data.reload)
|
|
348
|
+
return Promise.resolve(null);
|
|
349
|
+
const reload = ObjectUtils.isArray(data.reload) ? data.reload : [data.reload];
|
|
350
|
+
return Promise.all(reload.map(id => {
|
|
351
|
+
const nextControl = this.getControl(id);
|
|
352
|
+
if (!nextControl || controls.has(nextControl))
|
|
353
|
+
return Promise.resolve(null);
|
|
354
|
+
controls.add(nextControl);
|
|
355
|
+
return new Promise(resolve => {
|
|
356
|
+
nextControl.load().then(() => {
|
|
357
|
+
this.reloadControlsFrom(nextControl, controls).then(resolve);
|
|
358
|
+
});
|
|
359
|
+
});
|
|
360
|
+
}));
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
class DynamicFormControl extends FormControl {
|
|
364
|
+
constructor(control, group) {
|
|
365
|
+
super(group.model[control.id], { updateOn: control.data.updateOn || group.updateOn });
|
|
366
|
+
this.control = control;
|
|
367
|
+
this.group = group;
|
|
368
|
+
this.group.addControl(control.id, this);
|
|
369
|
+
this.helper = new DynamicFormControlHelper(this.form, control);
|
|
370
|
+
this.helper.findProvider(this);
|
|
371
|
+
this.valueChanges.subscribe(() => this.group.updateModel(this));
|
|
372
|
+
this.setAsyncValidators(createValidator(this));
|
|
373
|
+
}
|
|
374
|
+
get id() {
|
|
375
|
+
return this.helper.id;
|
|
376
|
+
}
|
|
377
|
+
get type() {
|
|
378
|
+
return this.helper.type;
|
|
379
|
+
}
|
|
380
|
+
get data() {
|
|
381
|
+
return this.helper.data;
|
|
382
|
+
}
|
|
383
|
+
get visible() {
|
|
384
|
+
return this.helper.visible;
|
|
385
|
+
}
|
|
386
|
+
get meta() {
|
|
387
|
+
return this.helper.meta;
|
|
388
|
+
}
|
|
389
|
+
get form() {
|
|
390
|
+
return this.group.form;
|
|
391
|
+
}
|
|
392
|
+
get injector() {
|
|
393
|
+
return this.form.injector;
|
|
394
|
+
}
|
|
395
|
+
get label() {
|
|
396
|
+
return this.data.label !== "" ? `${this.group.prefix}${this.data.label}` : "";
|
|
397
|
+
}
|
|
398
|
+
get provider() {
|
|
399
|
+
return this.helper.provider;
|
|
400
|
+
}
|
|
401
|
+
get model() {
|
|
402
|
+
return this.group.model;
|
|
403
|
+
}
|
|
404
|
+
get formId() {
|
|
405
|
+
return this.helper.formId;
|
|
406
|
+
}
|
|
407
|
+
getData() {
|
|
408
|
+
return this.data;
|
|
409
|
+
}
|
|
410
|
+
getControl(id) {
|
|
411
|
+
return null;
|
|
412
|
+
}
|
|
413
|
+
load() {
|
|
414
|
+
return this.helper.load(this);
|
|
415
|
+
}
|
|
416
|
+
check() {
|
|
417
|
+
const check = this.helper.check(this);
|
|
418
|
+
check.then(readonly => {
|
|
419
|
+
if (readonly || this.group.disabled)
|
|
420
|
+
this.disable({ emitEvent: false });
|
|
421
|
+
else
|
|
422
|
+
this.enable({ emitEvent: false });
|
|
423
|
+
});
|
|
424
|
+
return check;
|
|
425
|
+
}
|
|
426
|
+
shouldSerialize() {
|
|
427
|
+
return this.helper.shouldSerialize(this);
|
|
428
|
+
}
|
|
429
|
+
shouldValidate() {
|
|
430
|
+
return this.helper.shouldValidate(this);
|
|
431
|
+
}
|
|
432
|
+
serialize() {
|
|
433
|
+
return Promise.resolve(this.value);
|
|
434
|
+
}
|
|
435
|
+
onFocus() {
|
|
436
|
+
this.markAsUntouched({ onlySelf: true });
|
|
437
|
+
}
|
|
438
|
+
onBlur() {
|
|
439
|
+
this.markAsTouched({ onlySelf: true });
|
|
440
|
+
}
|
|
441
|
+
showErrors() {
|
|
442
|
+
this.markAsTouched({ onlySelf: true });
|
|
443
|
+
}
|
|
444
|
+
}
|
|
10
445
|
// --- Decorator functions ---
|
|
11
446
|
const emptyArray = [];
|
|
12
447
|
const emptyTester = () => {
|
|
@@ -14,8 +449,8 @@ const emptyTester = () => {
|
|
|
14
449
|
};
|
|
15
450
|
const ɵ0 = emptyTester;
|
|
16
451
|
function defaultSerializer(id, parent) {
|
|
17
|
-
const control = parent.
|
|
18
|
-
return !control ?
|
|
452
|
+
const control = parent.getControl(id);
|
|
453
|
+
return !control ? Promise.resolve(parent.model[id]) : control.serialize();
|
|
19
454
|
}
|
|
20
455
|
function FormSerializable(serializer) {
|
|
21
456
|
return (target, propertyKey) => {
|
|
@@ -66,6 +501,24 @@ function FormFieldSet(data) {
|
|
|
66
501
|
ReflectUtils.defineMetadata("dynamicFormFieldSets", sets, target);
|
|
67
502
|
};
|
|
68
503
|
}
|
|
504
|
+
function provideFormGroup(component) {
|
|
505
|
+
return {
|
|
506
|
+
provide: FORM_GROUP_TYPE,
|
|
507
|
+
useValue: component
|
|
508
|
+
};
|
|
509
|
+
}
|
|
510
|
+
function provideFormControl(component, acceptor, loader, priority = 0) {
|
|
511
|
+
return {
|
|
512
|
+
provide: FORM_CONTROL_PROVIDER,
|
|
513
|
+
multi: true,
|
|
514
|
+
useValue: {
|
|
515
|
+
component: component,
|
|
516
|
+
priority: priority,
|
|
517
|
+
acceptor: acceptor,
|
|
518
|
+
loader: loader
|
|
519
|
+
}
|
|
520
|
+
};
|
|
521
|
+
}
|
|
69
522
|
function defineFormControl(target, propertyKey, control) {
|
|
70
523
|
ReflectUtils.defineMetadata("dynamicFormControl", control, target, propertyKey);
|
|
71
524
|
}
|
|
@@ -98,15 +551,14 @@ function createFormInput(id, data, type = "text") {
|
|
|
98
551
|
data = control.data;
|
|
99
552
|
data.type = data.type || type;
|
|
100
553
|
data.classes = !data.classes ? `form-group-${data.type}` : `${data.classes} form-group-${data.type}`;
|
|
101
|
-
data.placeholder = data.placeholder ||
|
|
554
|
+
data.placeholder = data.placeholder || "";
|
|
102
555
|
data.step = data.step || 1;
|
|
103
|
-
data.mask = data.mask || [/\w*/gi];
|
|
104
556
|
return control;
|
|
105
557
|
}
|
|
106
558
|
function createFormSelect(id, data) {
|
|
107
559
|
const control = createFormControl(id, "select", data);
|
|
108
560
|
data = control.data;
|
|
109
|
-
data.options = data.options || [];
|
|
561
|
+
data.options = data.options || (() => Promise.resolve([]));
|
|
110
562
|
data.type = data.type || "select";
|
|
111
563
|
const classType = data.type == "select" ? "select" : `select-${data.type}`;
|
|
112
564
|
data.classes = !data.classes ? `form-group-${classType}` : `${data.classes} form-group-${classType}`;
|
|
@@ -139,447 +591,286 @@ function createFormFile(id, data) {
|
|
|
139
591
|
return control;
|
|
140
592
|
}
|
|
141
593
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
594
|
+
class DynamicFormService {
|
|
595
|
+
constructor(components, groupType, resolver, injector) {
|
|
596
|
+
this.components = components;
|
|
597
|
+
this.groupType = groupType;
|
|
598
|
+
this.resolver = resolver;
|
|
599
|
+
this.injector = injector;
|
|
600
|
+
}
|
|
601
|
+
findProvider(control) {
|
|
602
|
+
if (!control)
|
|
603
|
+
return null;
|
|
604
|
+
const providers = this.components.filter(p => p.acceptor(control));
|
|
605
|
+
if (providers.length == 0) {
|
|
606
|
+
throw new Error(`No component provider for control: ${JSON.stringify({
|
|
607
|
+
id: control.id,
|
|
608
|
+
type: control.type,
|
|
609
|
+
data: control.data
|
|
610
|
+
})}`);
|
|
611
|
+
}
|
|
612
|
+
// Sort providers
|
|
613
|
+
providers.sort((a, b) => ObjectUtils.compare(a.priority, b.priority));
|
|
614
|
+
return providers[0];
|
|
615
|
+
}
|
|
616
|
+
createComponent(vcr, provider) {
|
|
617
|
+
vcr.clear();
|
|
618
|
+
if (!provider)
|
|
619
|
+
return null;
|
|
620
|
+
const factory = this.resolver.resolveComponentFactory(provider.component);
|
|
621
|
+
return vcr.createComponent(factory).instance;
|
|
622
|
+
}
|
|
623
|
+
createGroup(vcr) {
|
|
624
|
+
vcr.clear();
|
|
625
|
+
const factory = this.resolver.resolveComponentFactory(this.groupType);
|
|
626
|
+
return vcr.createComponent(factory).instance;
|
|
152
627
|
}
|
|
153
628
|
}
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
const value = control.value;
|
|
164
|
-
if (!value)
|
|
165
|
-
return Promise.resolve(null);
|
|
166
|
-
const phoneRegexp = /^(?:\d){10,12}$/;
|
|
167
|
-
return phoneRegexp.test(value) ? null : { phone: true };
|
|
168
|
-
}
|
|
629
|
+
DynamicFormService.decorators = [
|
|
630
|
+
{ type: Injectable }
|
|
631
|
+
];
|
|
632
|
+
DynamicFormService.ctorParameters = () => [
|
|
633
|
+
{ type: Array, decorators: [{ type: Inject, args: [FORM_CONTROL_PROVIDER,] }] },
|
|
634
|
+
{ type: Type, decorators: [{ type: Inject, args: [FORM_GROUP_TYPE,] }] },
|
|
635
|
+
{ type: ComponentFactoryResolver },
|
|
636
|
+
{ type: Injector }
|
|
637
|
+
];
|
|
169
638
|
|
|
170
|
-
class
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
639
|
+
class FormUtilities {
|
|
640
|
+
static checkField(expression = `true`) {
|
|
641
|
+
// @dynamic
|
|
642
|
+
const lambda = (control) => {
|
|
643
|
+
return Promise.resolve(ObjectUtils.evaluate(expression, { control: control }));
|
|
644
|
+
};
|
|
645
|
+
return lambda;
|
|
174
646
|
}
|
|
175
|
-
|
|
176
|
-
return
|
|
177
|
-
let value = this.notifyCallback(controlModel, control);
|
|
178
|
-
if (value instanceof Promise) {
|
|
179
|
-
value = yield value;
|
|
180
|
-
}
|
|
181
|
-
this.next(value);
|
|
182
|
-
});
|
|
647
|
+
static checkReadonly(control) {
|
|
648
|
+
return Promise.resolve(control.visible && !control.disabled);
|
|
183
649
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
class DynamicFormArrayModel extends DynamicFormArrayModel$1 {
|
|
187
|
-
constructor(config, layout) {
|
|
188
|
-
super(config, layout);
|
|
189
|
-
this.additional = config.additional || {};
|
|
650
|
+
static readonly() {
|
|
651
|
+
return Promise.resolve(true);
|
|
190
652
|
}
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
}
|
|
202
|
-
get language() {
|
|
203
|
-
return this.api.language;
|
|
204
|
-
}
|
|
205
|
-
patchGroup(value, formModel, formGroup) {
|
|
206
|
-
this.patchValueRecursive(value, formModel, formGroup);
|
|
207
|
-
this.detectChanges();
|
|
208
|
-
formGroup.patchValue(ObjectUtils.copy(value));
|
|
209
|
-
}
|
|
210
|
-
patchForm(value, component) {
|
|
211
|
-
this.patchValueRecursive(value, component.model, component.group);
|
|
212
|
-
this.detectChanges(component);
|
|
213
|
-
component.group.patchValue(value);
|
|
214
|
-
}
|
|
215
|
-
serialize(formModel, formGroup) {
|
|
216
|
-
return this.serializeRecursive(formModel, formGroup);
|
|
217
|
-
}
|
|
218
|
-
notifyChanges(formModel, formGroup) {
|
|
219
|
-
this.notifyChangesRecursive(formModel, formGroup);
|
|
220
|
-
}
|
|
221
|
-
updateSelectOptions(formControlModel, formControl) {
|
|
222
|
-
if (formControlModel instanceof DynamicSelectModel) {
|
|
223
|
-
let options = formControlModel.options$;
|
|
224
|
-
if (options instanceof FormSubject) {
|
|
225
|
-
options.notify(formControlModel, formControl);
|
|
226
|
-
return;
|
|
227
|
-
}
|
|
228
|
-
while (options instanceof Subject && options.source) {
|
|
229
|
-
options = options.source;
|
|
230
|
-
if (options instanceof FormSubject) {
|
|
231
|
-
options.notify(formControlModel, formControl);
|
|
232
|
-
}
|
|
233
|
-
}
|
|
653
|
+
static validateJSON(control) {
|
|
654
|
+
const value = control.value;
|
|
655
|
+
if (!value)
|
|
656
|
+
return Promise.resolve(null);
|
|
657
|
+
try {
|
|
658
|
+
JSON.parse(value);
|
|
659
|
+
return Promise.resolve(null);
|
|
660
|
+
}
|
|
661
|
+
catch (e) {
|
|
662
|
+
return Promise.resolve("error.not-valid-json");
|
|
234
663
|
}
|
|
235
664
|
}
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
240
|
-
detectChanges(formComponent) {
|
|
241
|
-
super.detectChanges(formComponent);
|
|
242
|
-
this.onDetectChanges.emit(formComponent);
|
|
243
|
-
}
|
|
244
|
-
patchValueRecursive(value, formModel, formGroup) {
|
|
245
|
-
Object.keys(value).forEach(key => {
|
|
246
|
-
const subModel = this.findModelById(key, formModel);
|
|
247
|
-
const subValue = value[key];
|
|
248
|
-
if (!subModel)
|
|
249
|
-
return;
|
|
250
|
-
const subControl = this.findControlByModel(subModel, formGroup);
|
|
251
|
-
if (subModel instanceof DynamicSelectModel && ObjectUtils.isObject(subValue)) {
|
|
252
|
-
value[key] = subValue.id || subValue._id || subValue;
|
|
253
|
-
return;
|
|
254
|
-
}
|
|
255
|
-
if (subModel instanceof DynamicFormArrayModel$1) {
|
|
256
|
-
const length = Array.isArray(subValue) ? subValue.length : 0;
|
|
257
|
-
const subArray = subControl;
|
|
258
|
-
while (subModel.size > length) {
|
|
259
|
-
this.removeFormArrayGroup(0, subArray, subModel);
|
|
260
|
-
}
|
|
261
|
-
while (subModel.size < length) {
|
|
262
|
-
this.insertFormArrayGroup(subModel.size, subArray, subModel);
|
|
263
|
-
}
|
|
264
|
-
for (let i = 0; i < length; i++) {
|
|
265
|
-
const itemModel = subModel.get(i);
|
|
266
|
-
this.patchValueRecursive(subValue[i], itemModel.group, subArray.at(i));
|
|
267
|
-
}
|
|
268
|
-
return;
|
|
269
|
-
}
|
|
270
|
-
if (subModel instanceof DynamicFormGroupModel) {
|
|
271
|
-
this.patchValueRecursive(subValue, subModel.group, subControl);
|
|
272
|
-
}
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
serializeRecursive(formModel, formGroup) {
|
|
276
|
-
var _a, _b;
|
|
277
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
278
|
-
const result = {};
|
|
279
|
-
if (!formModel || !formGroup || !formGroup.value)
|
|
280
|
-
return result;
|
|
281
|
-
for (const i in formModel) {
|
|
282
|
-
const subModel = formModel[i];
|
|
283
|
-
const subControl = this.findControlByModel(subModel, formGroup);
|
|
284
|
-
const serializer = (_a = subModel.additional) === null || _a === void 0 ? void 0 : _a.serializer;
|
|
285
|
-
if (ObjectUtils.isFunction(serializer)) {
|
|
286
|
-
result[subModel.id] = yield serializer(subModel, subControl);
|
|
287
|
-
continue;
|
|
288
|
-
}
|
|
289
|
-
if (subModel instanceof DynamicFormArrayModel$1) {
|
|
290
|
-
const length = Array.isArray(subControl.value) ? subControl.value.length : 0;
|
|
291
|
-
const subArray = subControl;
|
|
292
|
-
const resArray = [];
|
|
293
|
-
for (let i = 0; i < length; i++) {
|
|
294
|
-
const itemModel = subModel.get(i);
|
|
295
|
-
resArray.push(yield this.serializeRecursive(itemModel.group, subArray.at(i)));
|
|
296
|
-
}
|
|
297
|
-
result[subModel.id] = resArray;
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
if (subModel instanceof DynamicFormGroupModel) {
|
|
301
|
-
result[subModel.id] = yield this.serializeRecursive(subModel.group, subControl);
|
|
302
|
-
continue;
|
|
303
|
-
}
|
|
304
|
-
if (subModel instanceof DynamicInputModel && !ObjectUtils.isNullOrUndefined(subControl.value)) {
|
|
305
|
-
result[subModel.id] = subModel.inputType == "number"
|
|
306
|
-
? (_b = parseFloat((`${subControl.value}` || "0").replace(/,/gi, "."))) !== null && _b !== void 0 ? _b : null : subControl.value;
|
|
307
|
-
continue;
|
|
308
|
-
}
|
|
309
|
-
result[subModel.id] = subControl.value;
|
|
310
|
-
}
|
|
311
|
-
return result;
|
|
312
|
-
});
|
|
665
|
+
static validateRequired(control) {
|
|
666
|
+
const value = control.value;
|
|
667
|
+
return Promise.resolve(!ObjectUtils.isNumber(value) && !value ? "error.required" : null);
|
|
313
668
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
if (subModel instanceof DynamicFormArrayModel$1) {
|
|
321
|
-
const length = Array.isArray(subControl.value) ? subControl.value.length : 0;
|
|
322
|
-
const subArray = subControl;
|
|
323
|
-
for (let i = 0; i < length; i++) {
|
|
324
|
-
const itemModel = subModel.get(i);
|
|
325
|
-
this.notifyChangesRecursive(itemModel.group, subArray.at(i));
|
|
326
|
-
}
|
|
327
|
-
continue;
|
|
669
|
+
static validateMinLength(length) {
|
|
670
|
+
// @dynamic
|
|
671
|
+
const lambda = (control) => {
|
|
672
|
+
const value = control.value;
|
|
673
|
+
if (!ObjectUtils.isString(value) || value.length < length) {
|
|
674
|
+
return Promise.resolve({ "error.min-length": { length: length } });
|
|
328
675
|
}
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
676
|
+
return Promise.resolve(null);
|
|
677
|
+
};
|
|
678
|
+
return lambda;
|
|
679
|
+
}
|
|
680
|
+
static validateMaxLength(length) {
|
|
681
|
+
// @dynamic
|
|
682
|
+
const lambda = (control) => {
|
|
683
|
+
const value = control.value;
|
|
684
|
+
if (!ObjectUtils.isString(value) || value.length > length) {
|
|
685
|
+
return Promise.resolve({ "error.max-length": { length: length } });
|
|
332
686
|
}
|
|
333
|
-
|
|
334
|
-
}
|
|
687
|
+
return Promise.resolve(null);
|
|
688
|
+
};
|
|
689
|
+
return lambda;
|
|
690
|
+
}
|
|
691
|
+
static validateRequiredTranslation(control) {
|
|
692
|
+
const value = control.value;
|
|
693
|
+
if (!value || value.length == 0)
|
|
694
|
+
return Promise.resolve("error.required");
|
|
695
|
+
return Promise.resolve(value.findIndex(t => (t.lang == "de" || t.lang == "en") && !t.translation) < 0 ? null : "error.required");
|
|
696
|
+
}
|
|
697
|
+
static validateEmail(control) {
|
|
698
|
+
const value = control.value;
|
|
699
|
+
if (!value)
|
|
700
|
+
return Promise.resolve(null);
|
|
701
|
+
const emailRegexp = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
|
702
|
+
return Promise.resolve(emailRegexp.test(value) ? null : "error.invalid-email");
|
|
703
|
+
}
|
|
704
|
+
static validatePhone(control) {
|
|
705
|
+
const value = control.value;
|
|
706
|
+
if (!value)
|
|
707
|
+
return Promise.resolve(null);
|
|
708
|
+
const phoneRegexp = /^(?:\d){10,12}$/;
|
|
709
|
+
return Promise.resolve(phoneRegexp.test(value) ? null : "error.invalid-phone");
|
|
710
|
+
}
|
|
711
|
+
static serializeLogo(id, parent) {
|
|
712
|
+
const value = parent.model[id];
|
|
713
|
+
return Promise.resolve(!value || value.length == 0 ? null : value);
|
|
714
|
+
}
|
|
715
|
+
static serializeFile(id, parent) {
|
|
716
|
+
const value = parent.model[id];
|
|
717
|
+
if (ObjectUtils.isBlob(value))
|
|
718
|
+
return Promise.resolve(value);
|
|
719
|
+
return Promise.resolve(!ObjectUtils.isString(value) || !value.startsWith("data:") ? null : FileUtils.dataToBlob(value));
|
|
720
|
+
}
|
|
721
|
+
static serializeNumber(id, parent) {
|
|
722
|
+
const value = parent.model[id];
|
|
723
|
+
return Promise.resolve(!value || value.length == 0 ? 0 : parseFloat(value));
|
|
724
|
+
}
|
|
725
|
+
static serializeJSON(id, parent) {
|
|
726
|
+
const value = parent.model[id];
|
|
727
|
+
return Promise.resolve(!value ? {} : JSON.parse(value));
|
|
728
|
+
}
|
|
729
|
+
static serializeDate(date, format = "yyyy-MM-dd", defaultValue = "") {
|
|
730
|
+
// @dynamic
|
|
731
|
+
const lambda = (id, parent) => {
|
|
732
|
+
const value = parent.model[id];
|
|
733
|
+
if (!ObjectUtils.isDate(value))
|
|
734
|
+
return Promise.resolve(value || defaultValue);
|
|
735
|
+
return Promise.resolve(!format ? value : date.transform(value, format));
|
|
736
|
+
};
|
|
737
|
+
return lambda;
|
|
335
738
|
}
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
}
|
|
353
|
-
});
|
|
739
|
+
}
|
|
740
|
+
__decorate([
|
|
741
|
+
FactoryDependencies(DatePipe)
|
|
742
|
+
], FormUtilities, "serializeDate", null);
|
|
743
|
+
|
|
744
|
+
class OpenApiService {
|
|
745
|
+
constructor(api) {
|
|
746
|
+
this.api = api;
|
|
747
|
+
const baseUrl = this.api.url("").replace("api/", "api-docs");
|
|
748
|
+
this.schemas = {};
|
|
749
|
+
this.schemasPromise = new Promise((resolve => {
|
|
750
|
+
this.api.client.get(baseUrl).subscribe((res) => {
|
|
751
|
+
this.schemas = res.definitions || {};
|
|
752
|
+
resolve(this.schemas);
|
|
753
|
+
}, () => {
|
|
754
|
+
resolve({});
|
|
755
|
+
});
|
|
756
|
+
}));
|
|
354
757
|
}
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
758
|
+
getFormInputsForSchema(name) {
|
|
759
|
+
this.api.cache = {};
|
|
760
|
+
return this.schemasPromise.then(schemas => {
|
|
761
|
+
const schema = schemas[name];
|
|
762
|
+
const inputs = this.getFormInputsForSchemaDef(schema);
|
|
763
|
+
return inputs;
|
|
360
764
|
});
|
|
361
765
|
}
|
|
362
|
-
|
|
766
|
+
getFormInputsForSchemaDef(schema) {
|
|
767
|
+
const inputs = {};
|
|
363
768
|
if (!schema)
|
|
364
|
-
return
|
|
365
|
-
|
|
769
|
+
return inputs;
|
|
770
|
+
inputs.schema = schema;
|
|
771
|
+
inputs.serializers = {};
|
|
772
|
+
inputs.controls = Object.keys(schema.properties || {}).map(p => {
|
|
366
773
|
const property = schema.properties[p];
|
|
367
|
-
|
|
774
|
+
property.id = p;
|
|
775
|
+
inputs.serializers[p] = (id, parent) => {
|
|
776
|
+
return Promise.resolve(parent.model[id]);
|
|
777
|
+
};
|
|
778
|
+
return this.getFormControlForProperty(property, schema);
|
|
368
779
|
}).filter(t => null !== t);
|
|
780
|
+
return inputs;
|
|
369
781
|
}
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
return new DynamicSelectModel(this.getFormSelectConfig(property, schema));
|
|
782
|
+
getFormControlForProperty(property, schema) {
|
|
783
|
+
if (Array.isArray(property.enum)) {
|
|
784
|
+
return createFormSelect(property.id, this.getFormSelectData(property, schema));
|
|
374
785
|
}
|
|
375
786
|
switch (property.type) {
|
|
376
787
|
case "string":
|
|
377
788
|
case "number":
|
|
378
|
-
case "integer":
|
|
379
|
-
return new DynamicInputModel(this.getFormInputConfig(property, schema));
|
|
380
|
-
case "textarea":
|
|
381
|
-
return new DynamicTextAreaModel(this.getFormTextareaConfig(property, schema));
|
|
382
789
|
case "boolean":
|
|
383
|
-
|
|
790
|
+
case "textarea":
|
|
791
|
+
return createFormInput(property.id, this.getFormInputData(property, schema));
|
|
384
792
|
case "list":
|
|
385
|
-
return
|
|
386
|
-
case "array":
|
|
387
|
-
if (((_a = property.items) === null || _a === void 0 ? void 0 : _a.$ref) || property.$ref) {
|
|
388
|
-
return new DynamicFormArrayModel(this.getFormArrayConfig(property, schema));
|
|
389
|
-
}
|
|
390
|
-
else if (((_b = property.items) === null || _b === void 0 ? void 0 : _b.enum) || property.enum) {
|
|
391
|
-
return new DynamicSelectModel(this.getFormSelectConfig(property, schema));
|
|
392
|
-
}
|
|
393
|
-
else {
|
|
394
|
-
return new DynamicInputModel(this.getFormInputConfig(property, schema));
|
|
395
|
-
}
|
|
793
|
+
return createFormSelect(property.id, this.getFormSelectData(property, schema));
|
|
396
794
|
case "file":
|
|
397
|
-
return
|
|
398
|
-
}
|
|
399
|
-
if (property.$ref) {
|
|
400
|
-
return new DynamicFormGroupModel(this.getFormGroupConfig(property, schema));
|
|
795
|
+
return createFormFile(property.id, this.getFormFileData(property, schema));
|
|
401
796
|
}
|
|
402
797
|
return null;
|
|
403
798
|
}
|
|
404
|
-
|
|
405
|
-
const validators = this.getValidators(property, schema);
|
|
406
|
-
const errorMessages = Object.keys(validators).reduce((res, key) => {
|
|
407
|
-
res[key] = `error.${key}`;
|
|
408
|
-
return res;
|
|
409
|
-
}, {});
|
|
799
|
+
getBaseFormData(property, schema) {
|
|
410
800
|
return {
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
disabled: property.disabled,
|
|
415
|
-
validators,
|
|
416
|
-
errorMessages,
|
|
417
|
-
additional: Object.assign({}, property)
|
|
801
|
+
readonly: property.readonly ? FormUtilities.readonly : null,
|
|
802
|
+
shouldSerialize: FormUtilities.checkReadonly,
|
|
803
|
+
validators: this.getValidators(property, schema)
|
|
418
804
|
};
|
|
419
805
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
const subSchema = this.schemas[ref.split("/").pop()];
|
|
424
|
-
return Object.assign(this.getFormControlConfig(property, schema), { groupFactory: () => this.getFormModelForSchemaDef(subSchema) });
|
|
425
|
-
}
|
|
426
|
-
getFormGroupConfig(property, schema) {
|
|
427
|
-
const ref = property.$ref || "";
|
|
428
|
-
const subSchema = this.schemas[ref.split("/").pop()];
|
|
429
|
-
return Object.assign(this.getFormControlConfig(property, schema), { group: this.getFormModelForSchemaDef(subSchema) });
|
|
430
|
-
}
|
|
431
|
-
getFormInputConfig(property, schema) {
|
|
432
|
-
var _a;
|
|
433
|
-
let inputType = StringUtils.has(property.id, "password", "Password") ? "password" : (((_a = property.items) === null || _a === void 0 ? void 0 : _a.type) || property.type);
|
|
434
|
-
switch (inputType) {
|
|
806
|
+
getFormInputData(property, schema) {
|
|
807
|
+
let type = StringUtils.has(property.id, "password", "Password") ? "password" : property.type;
|
|
808
|
+
switch (property.type) {
|
|
435
809
|
case "boolean":
|
|
436
|
-
|
|
810
|
+
type = "checkbox";
|
|
437
811
|
break;
|
|
438
812
|
case "textarea":
|
|
439
|
-
|
|
440
|
-
break;
|
|
441
|
-
case "integer":
|
|
442
|
-
inputType = "number";
|
|
813
|
+
type = "textarea";
|
|
443
814
|
break;
|
|
444
815
|
}
|
|
445
|
-
return Object.assign(this.
|
|
446
|
-
inputType,
|
|
447
|
-
autoComplete: property.autoComplete || "off",
|
|
448
|
-
multiple: property.type == "array",
|
|
449
|
-
accept: ObjectUtils.isString(property.accept) ? property.accept : null,
|
|
450
|
-
mask: ObjectUtils.isString(property.mask) ? property.mask : null,
|
|
451
|
-
pattern: ObjectUtils.isString(property.pattern) ? property.pattern : null,
|
|
452
|
-
step: isNaN(property.step) ? 1 : property.step,
|
|
453
|
-
min: isNaN(property.min) ? Number.MIN_SAFE_INTEGER : property.min,
|
|
454
|
-
max: isNaN(property.max) ? Number.MAX_SAFE_INTEGER : property.max,
|
|
455
|
-
});
|
|
456
|
-
}
|
|
457
|
-
getFormTextareaConfig(property, schema) {
|
|
458
|
-
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
459
|
-
cols: property.cols || null,
|
|
460
|
-
rows: property.rows || 10,
|
|
461
|
-
wrap: property.wrap || false,
|
|
462
|
-
autoComplete: property.autoComplete || "off",
|
|
463
|
-
multiple: property.type == "array"
|
|
464
|
-
});
|
|
816
|
+
return Object.assign(Object.assign({}, this.getBaseFormData(property, schema)), { type });
|
|
465
817
|
}
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
});
|
|
471
|
-
}
|
|
472
|
-
getFormCheckboxConfig(property, schema) {
|
|
473
|
-
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
474
|
-
indeterminate: property.indeterminate === true
|
|
475
|
-
});
|
|
476
|
-
}
|
|
477
|
-
translateOptions(options) {
|
|
478
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
479
|
-
if (!options)
|
|
480
|
-
return [];
|
|
481
|
-
for (const option of options) {
|
|
482
|
-
option.label = yield this.language.getTranslation(option.label);
|
|
818
|
+
getFormSelectData(property, schema) {
|
|
819
|
+
const options = Array.isArray(property.enum)
|
|
820
|
+
? () => {
|
|
821
|
+
return Promise.resolve(property.enum.map(id => ({ id, label: `${property.id}.${id}` })));
|
|
483
822
|
}
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
const $enum = ((_a = property.items) === null || _a === void 0 ? void 0 : _a.enum) || property.enum;
|
|
490
|
-
if (property.optionsPath) {
|
|
491
|
-
return new FormSubject((formModel, control) => {
|
|
492
|
-
let path = property.optionsPath;
|
|
493
|
-
let target = control;
|
|
494
|
-
if (path.startsWith("$root")) {
|
|
495
|
-
path = path.substr(5);
|
|
496
|
-
while (target.parent) {
|
|
497
|
-
target = target.parent;
|
|
498
|
-
}
|
|
499
|
-
}
|
|
500
|
-
while (path.startsWith(".")) {
|
|
501
|
-
path = path.substr(1);
|
|
502
|
-
if (target.parent) {
|
|
503
|
-
target = target.parent;
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
const value = ObjectUtils.getValue(target.value, path);
|
|
507
|
-
const options = (!ObjectUtils.isArray(value) ? [] : value).map(value => ({ value, label: value }));
|
|
508
|
-
return this.translateOptions(options);
|
|
509
|
-
});
|
|
510
|
-
}
|
|
511
|
-
if (ObjectUtils.isArray($enum)) {
|
|
512
|
-
return new FormSubject(() => {
|
|
513
|
-
const options = $enum.map(value => {
|
|
514
|
-
const label = property.translatable ? `${property.id}.${value}` : value;
|
|
515
|
-
return { value, label };
|
|
516
|
-
});
|
|
517
|
-
return this.translateOptions(options);
|
|
518
|
-
});
|
|
519
|
-
}
|
|
520
|
-
return new FormSubject(() => __awaiter(this, void 0, void 0, function* () {
|
|
521
|
-
this.api.cache[property.endpoint] = this.api.cache[property.endpoint] || this.api.list(property.endpoint, this.api.makeListParams(1, -1)).then(result => {
|
|
522
|
-
return result.items.map(i => {
|
|
523
|
-
return { value: i.id || i._id, label: i[property.labelField] || i.label || i.id || i._id };
|
|
823
|
+
: () => {
|
|
824
|
+
this.api.cache[property.endpoint] = this.api.cache[property.endpoint] || this.api.list(property.endpoint, this.api.makeListParams(1, -1)).then(result => {
|
|
825
|
+
return result.items.map(i => {
|
|
826
|
+
return { id: i._id, label: i.name };
|
|
827
|
+
});
|
|
524
828
|
});
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
}));
|
|
829
|
+
return this.api.cache[property.endpoint];
|
|
830
|
+
};
|
|
831
|
+
return Object.assign(Object.assign({}, this.getBaseFormData(property, schema)), { options });
|
|
529
832
|
}
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
const { accept, autoUpload, maxSize, minSize, removeUrl, showFileList } = property;
|
|
533
|
-
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
534
|
-
url,
|
|
535
|
-
accept,
|
|
536
|
-
autoUpload,
|
|
537
|
-
maxSize,
|
|
538
|
-
minSize,
|
|
539
|
-
removeUrl,
|
|
540
|
-
showFileList
|
|
541
|
-
});
|
|
833
|
+
getFormFileData(property, schema) {
|
|
834
|
+
return Object.assign(Object.assign({}, this.getBaseFormData(property, schema)), { multi: property.multi });
|
|
542
835
|
}
|
|
543
836
|
getValidators(property, schema) {
|
|
544
|
-
const validators =
|
|
545
|
-
if (
|
|
546
|
-
validators.
|
|
837
|
+
const validators = [];
|
|
838
|
+
if (schema.required.indexOf(property.id) >= 0) {
|
|
839
|
+
validators.push(FormUtilities.validateRequired);
|
|
547
840
|
}
|
|
548
841
|
if (property.minLength) {
|
|
549
|
-
validators.
|
|
842
|
+
validators.push({
|
|
843
|
+
type: FormUtilities,
|
|
844
|
+
func: FormUtilities.validateMinLength,
|
|
845
|
+
params: [property.minLength]
|
|
846
|
+
});
|
|
550
847
|
}
|
|
551
848
|
if (property.maxLength) {
|
|
552
|
-
validators.
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
if (property.max) {
|
|
558
|
-
validators.max = property.max;
|
|
849
|
+
validators.push({
|
|
850
|
+
type: FormUtilities,
|
|
851
|
+
func: FormUtilities.validateMaxLength,
|
|
852
|
+
params: [property.maxLength]
|
|
853
|
+
});
|
|
559
854
|
}
|
|
560
855
|
switch (property.format) {
|
|
561
856
|
case "email":
|
|
562
|
-
validators.
|
|
857
|
+
validators.push(FormUtilities.validateEmail);
|
|
563
858
|
break;
|
|
564
859
|
}
|
|
565
860
|
return validators;
|
|
566
861
|
}
|
|
567
862
|
}
|
|
568
|
-
|
|
863
|
+
OpenApiService.decorators = [
|
|
569
864
|
{ type: Injectable }
|
|
570
865
|
];
|
|
571
|
-
|
|
572
|
-
{ type:
|
|
573
|
-
{ type: DynamicFormValidationService$1 },
|
|
574
|
-
{ type: OpenApiService }
|
|
866
|
+
OpenApiService.ctorParameters = () => [
|
|
867
|
+
{ type: ApiService }
|
|
575
868
|
];
|
|
576
869
|
|
|
577
870
|
class AsyncSubmitDirective {
|
|
578
871
|
constructor(toaster, cdr, elem, renderer) {
|
|
579
872
|
this.toaster = toaster;
|
|
580
873
|
this.cdr = cdr;
|
|
581
|
-
this.elem = elem;
|
|
582
|
-
this.renderer = renderer;
|
|
583
874
|
this.onSuccess = new EventEmitter();
|
|
584
875
|
this.onError = new EventEmitter();
|
|
585
876
|
if (elem.nativeElement.tagName !== "BUTTON")
|
|
@@ -589,26 +880,18 @@ class AsyncSubmitDirective {
|
|
|
589
880
|
get isDisabled() {
|
|
590
881
|
return this.disabled;
|
|
591
882
|
}
|
|
592
|
-
set isDisabled(value) {
|
|
593
|
-
this.disabled = value;
|
|
594
|
-
if (value) {
|
|
595
|
-
this.renderer.setAttribute(this.elem.nativeElement, "disabled", "disabled");
|
|
596
|
-
return;
|
|
597
|
-
}
|
|
598
|
-
this.renderer.removeAttribute(this.elem.nativeElement, "disabled");
|
|
599
|
-
}
|
|
600
883
|
get isLoading() {
|
|
601
884
|
return this.loading;
|
|
602
885
|
}
|
|
603
886
|
ngOnInit() {
|
|
604
887
|
if (!this.form)
|
|
605
888
|
return;
|
|
606
|
-
this.
|
|
889
|
+
this.disabled = this.form.status !== "VALID";
|
|
607
890
|
this.cdr.detectChanges();
|
|
608
|
-
this.onStatusChange = this.form.onStatusChange.subscribe(
|
|
609
|
-
this.
|
|
891
|
+
this.onStatusChange = this.form.onStatusChange.subscribe(form => {
|
|
892
|
+
this.disabled = form.status !== "VALID";
|
|
610
893
|
this.cdr.detectChanges();
|
|
611
|
-
if (!this.callback ||
|
|
894
|
+
if (!this.callback || form.status == "PENDING")
|
|
612
895
|
return;
|
|
613
896
|
if (!this.disabled) {
|
|
614
897
|
this.callback();
|
|
@@ -634,7 +917,7 @@ class AsyncSubmitDirective {
|
|
|
634
917
|
if (this.loading)
|
|
635
918
|
return;
|
|
636
919
|
this.loading = true;
|
|
637
|
-
this.method(this.form
|
|
920
|
+
this.method(this.form).then(result => {
|
|
638
921
|
this.loading = false;
|
|
639
922
|
if (result) {
|
|
640
923
|
this.onSuccess.emit(result);
|
|
@@ -664,7 +947,6 @@ AsyncSubmitDirective.ctorParameters = () => [
|
|
|
664
947
|
AsyncSubmitDirective.propDecorators = {
|
|
665
948
|
method: [{ type: Input, args: ["async-submit",] }],
|
|
666
949
|
form: [{ type: Input }],
|
|
667
|
-
context: [{ type: Input }],
|
|
668
950
|
onSuccess: [{ type: Output }],
|
|
669
951
|
onError: [{ type: Output }],
|
|
670
952
|
isDisabled: [{ type: HostBinding, args: ["class.disabled",] }],
|
|
@@ -672,78 +954,194 @@ AsyncSubmitDirective.propDecorators = {
|
|
|
672
954
|
click: [{ type: HostListener, args: ["click",] }]
|
|
673
955
|
};
|
|
674
956
|
|
|
675
|
-
class
|
|
676
|
-
constructor(
|
|
677
|
-
|
|
957
|
+
class DynamicFormControlDirective {
|
|
958
|
+
constructor(vcr, forms) {
|
|
959
|
+
this.vcr = vcr;
|
|
960
|
+
this.forms = forms;
|
|
961
|
+
}
|
|
962
|
+
get component() {
|
|
963
|
+
return this.comp;
|
|
964
|
+
}
|
|
965
|
+
ngOnChanges(changes) {
|
|
966
|
+
if (changes.control) {
|
|
967
|
+
this.comp = this.forms.createComponent(this.vcr, this.control.provider);
|
|
968
|
+
}
|
|
969
|
+
if (!this.comp)
|
|
970
|
+
return;
|
|
971
|
+
this.comp.control = this.control;
|
|
972
|
+
}
|
|
973
|
+
}
|
|
974
|
+
DynamicFormControlDirective.decorators = [
|
|
975
|
+
{ type: Directive, args: [{
|
|
976
|
+
selector: "[form-control]",
|
|
977
|
+
},] }
|
|
978
|
+
];
|
|
979
|
+
DynamicFormControlDirective.ctorParameters = () => [
|
|
980
|
+
{ type: ViewContainerRef },
|
|
981
|
+
{ type: DynamicFormService }
|
|
982
|
+
];
|
|
983
|
+
DynamicFormControlDirective.propDecorators = {
|
|
984
|
+
control: [{ type: Input, args: ["form-control",] }]
|
|
985
|
+
};
|
|
986
|
+
|
|
987
|
+
class DynamicFormTemplateDirective {
|
|
988
|
+
constructor(template) {
|
|
989
|
+
this.template = template;
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
DynamicFormTemplateDirective.decorators = [
|
|
993
|
+
{ type: Directive, args: [{
|
|
994
|
+
selector: `ng-template[control],
|
|
995
|
+
ng-template[label],
|
|
996
|
+
ng-template[input],
|
|
997
|
+
ng-template[prefix],
|
|
998
|
+
ng-template[suffix],
|
|
999
|
+
ng-template[setPrefix],
|
|
1000
|
+
ng-template[setSuffix],
|
|
1001
|
+
ng-template[formPrefix],
|
|
1002
|
+
ng-template[formSuffix],
|
|
1003
|
+
ng-template[innerFormPrefix],
|
|
1004
|
+
ng-template[innerFormSuffix]`
|
|
1005
|
+
},] }
|
|
1006
|
+
];
|
|
1007
|
+
DynamicFormTemplateDirective.ctorParameters = () => [
|
|
1008
|
+
{ type: TemplateRef }
|
|
1009
|
+
];
|
|
1010
|
+
DynamicFormTemplateDirective.propDecorators = {
|
|
1011
|
+
control: [{ type: Input }],
|
|
1012
|
+
label: [{ type: Input }],
|
|
1013
|
+
input: [{ type: Input }],
|
|
1014
|
+
prefix: [{ type: Input }],
|
|
1015
|
+
suffix: [{ type: Input }],
|
|
1016
|
+
setPrefix: [{ type: Input }],
|
|
1017
|
+
setSuffix: [{ type: Input }],
|
|
1018
|
+
formPrefix: [{ type: Input }],
|
|
1019
|
+
formSuffix: [{ type: Input }],
|
|
1020
|
+
innerFormPrefix: [{ type: Input }],
|
|
1021
|
+
innerFormSuffix: [{ type: Input }]
|
|
1022
|
+
};
|
|
1023
|
+
|
|
1024
|
+
class DynamicFormBaseComponent {
|
|
1025
|
+
constructor(cdr, formService) {
|
|
678
1026
|
this.formService = formService;
|
|
679
|
-
this.
|
|
680
|
-
this.
|
|
681
|
-
this.
|
|
682
|
-
this.
|
|
1027
|
+
this.name = "";
|
|
1028
|
+
this.controlTemplates = {};
|
|
1029
|
+
this.labelTemplates = {};
|
|
1030
|
+
this.inputTemplates = {};
|
|
1031
|
+
this.prefixTemplates = {};
|
|
1032
|
+
this.suffixTemplates = {};
|
|
1033
|
+
this.onChange = new EventEmitter();
|
|
683
1034
|
this.onStatusChange = new EventEmitter();
|
|
684
|
-
this.
|
|
1035
|
+
this.onInit = new EventEmitter();
|
|
685
1036
|
this.onSubmit = new EventEmitter();
|
|
686
|
-
this.
|
|
687
|
-
this.
|
|
688
|
-
this.groupSubscription = new Subscription();
|
|
689
|
-
this.labelPrefix = "label";
|
|
690
|
-
}
|
|
691
|
-
get status() {
|
|
692
|
-
return !this.group ? null : this.group.status;
|
|
1037
|
+
this.injector = formService.injector;
|
|
1038
|
+
this.cdr = cdr;
|
|
693
1039
|
}
|
|
694
|
-
|
|
695
|
-
this
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
this.onStatusChange.emit(this);
|
|
699
|
-
}), this.group.valueChanges.subscribe(() => {
|
|
700
|
-
this.onValueChange.emit(this);
|
|
701
|
-
this.formService.notifyChanges(this.model, this.group);
|
|
702
|
-
}));
|
|
1040
|
+
get root() {
|
|
1041
|
+
let form = this;
|
|
1042
|
+
while (ObjectUtils.isDefined(form.parent)) {
|
|
1043
|
+
form = form.parent;
|
|
703
1044
|
}
|
|
1045
|
+
return form;
|
|
704
1046
|
}
|
|
705
|
-
|
|
706
|
-
this.
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
1047
|
+
findProvider(control) {
|
|
1048
|
+
return this.formService.findProvider(control);
|
|
1049
|
+
}
|
|
1050
|
+
// --- Lifecycle hooks
|
|
1051
|
+
ngAfterContentInit() {
|
|
1052
|
+
this.wrapperTemplate = this.wrapperTemplate || this.cWrapperTemplate;
|
|
1053
|
+
this.fieldSetTemplate = this.fieldSetTemplate || this.cFieldSetTemplate;
|
|
1054
|
+
this.controlTemplate = this.controlTemplate || this.cControlTemplate;
|
|
1055
|
+
this.controlTemplates = this.filterTemplates(this.controlTemplates, "control");
|
|
1056
|
+
this.labelTemplates = this.filterTemplates(this.labelTemplates, "label");
|
|
1057
|
+
this.inputTemplates = this.filterTemplates(this.inputTemplates, "input");
|
|
1058
|
+
this.prefixTemplates = this.filterTemplates(this.prefixTemplates, "prefix");
|
|
1059
|
+
this.suffixTemplates = this.filterTemplates(this.suffixTemplates, "suffix");
|
|
1060
|
+
this.setPrefixTemplates = this.filterTemplates(this.setPrefixTemplates, "setPrefix");
|
|
1061
|
+
this.setSuffixTemplates = this.filterTemplates(this.setSuffixTemplates, "setSuffix");
|
|
1062
|
+
}
|
|
1063
|
+
filterTemplates(templates, type) {
|
|
1064
|
+
if (ObjectUtils.isObject(templates) && Object.keys(templates).length > 0)
|
|
1065
|
+
return templates;
|
|
1066
|
+
return this.templates.filter(t => !!t[type]).reduce((result, directive) => {
|
|
1067
|
+
result[directive[type]] = directive.template;
|
|
1068
|
+
return result;
|
|
1069
|
+
}, {});
|
|
717
1070
|
}
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
1071
|
+
}
|
|
1072
|
+
DynamicFormBaseComponent.decorators = [
|
|
1073
|
+
{ type: Directive }
|
|
1074
|
+
];
|
|
1075
|
+
DynamicFormBaseComponent.ctorParameters = () => [
|
|
1076
|
+
{ type: ChangeDetectorRef },
|
|
1077
|
+
{ type: DynamicFormService }
|
|
1078
|
+
];
|
|
1079
|
+
DynamicFormBaseComponent.propDecorators = {
|
|
1080
|
+
name: [{ type: Input }],
|
|
1081
|
+
readonly: [{ type: Input }],
|
|
1082
|
+
updateOn: [{ type: Input }],
|
|
1083
|
+
classes: [{ type: Input }],
|
|
1084
|
+
parent: [{ type: Input }],
|
|
1085
|
+
wrapperTemplate: [{ type: Input }],
|
|
1086
|
+
fieldSetTemplate: [{ type: Input }],
|
|
1087
|
+
controlTemplate: [{ type: Input }],
|
|
1088
|
+
controlTemplates: [{ type: Input }],
|
|
1089
|
+
labelTemplates: [{ type: Input }],
|
|
1090
|
+
inputTemplates: [{ type: Input }],
|
|
1091
|
+
prefixTemplates: [{ type: Input }],
|
|
1092
|
+
suffixTemplates: [{ type: Input }],
|
|
1093
|
+
setPrefixTemplates: [{ type: Input }],
|
|
1094
|
+
setSuffixTemplates: [{ type: Input }],
|
|
1095
|
+
onChange: [{ type: Output }],
|
|
1096
|
+
onStatusChange: [{ type: Output }],
|
|
1097
|
+
onInit: [{ type: Output }],
|
|
1098
|
+
onSubmit: [{ type: Output }],
|
|
1099
|
+
prefixTemplate: [{ type: ContentChild, args: ["prefixTemplate",] }],
|
|
1100
|
+
suffixTemplate: [{ type: ContentChild, args: ["suffixTemplate",] }],
|
|
1101
|
+
templates: [{ type: ContentChildren, args: [DynamicFormTemplateDirective,] }],
|
|
1102
|
+
cWrapperTemplate: [{ type: ContentChild, args: ["wrapperTemplate",] }],
|
|
1103
|
+
cFieldSetTemplate: [{ type: ContentChild, args: ["fieldSetTemplate",] }],
|
|
1104
|
+
cControlTemplate: [{ type: ContentChild, args: ["controlTemplate",] }]
|
|
1105
|
+
};
|
|
1106
|
+
|
|
1107
|
+
class DynamicFormComponent extends DynamicFormBaseComponent {
|
|
1108
|
+
constructor(cdr, forms) {
|
|
1109
|
+
super(cdr, forms);
|
|
1110
|
+
this.group = new DynamicFormGroup(this);
|
|
1111
|
+
this.defaultFieldSet = {
|
|
1112
|
+
id: "",
|
|
1113
|
+
title: "",
|
|
1114
|
+
classes: ""
|
|
1115
|
+
};
|
|
722
1116
|
}
|
|
723
|
-
|
|
724
|
-
this.
|
|
725
|
-
this.changeDetectorRef.detectChanges();
|
|
1117
|
+
get status() {
|
|
1118
|
+
return this.group.state;
|
|
726
1119
|
}
|
|
727
|
-
|
|
728
|
-
this.
|
|
729
|
-
this.changeDetectorRef.detectChanges();
|
|
1120
|
+
get formControls() {
|
|
1121
|
+
return this.group.formControls;
|
|
730
1122
|
}
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
this.
|
|
1123
|
+
// --- Lifecycle hooks
|
|
1124
|
+
ngOnChanges(changes) {
|
|
1125
|
+
if (!this.data)
|
|
1126
|
+
return;
|
|
1127
|
+
if (changes.data || changes.controls || changes.serializers || changes.formGroup) {
|
|
1128
|
+
if (this.group.id)
|
|
1129
|
+
return;
|
|
1130
|
+
this.group.setup(this.data, this);
|
|
1131
|
+
this.group.reloadControls();
|
|
1132
|
+
}
|
|
734
1133
|
}
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
this.
|
|
1134
|
+
// --- Custom ---
|
|
1135
|
+
onFormSubmit() {
|
|
1136
|
+
const root = this.root;
|
|
1137
|
+
root.validate().then(() => root.onSubmit.emit(this), () => { });
|
|
738
1138
|
}
|
|
1139
|
+
// --- IDynamicForm ---
|
|
739
1140
|
validate(showErrors = true) {
|
|
740
|
-
if (!this.group)
|
|
741
|
-
return Promise.resolve();
|
|
742
1141
|
return new Promise((resolve, reject) => {
|
|
743
1142
|
this.group.statusChanges.pipe(first(status => status == "VALID" || status == "INVALID")).subscribe(status => {
|
|
744
|
-
if (showErrors)
|
|
745
|
-
this.
|
|
746
|
-
}
|
|
1143
|
+
if (showErrors)
|
|
1144
|
+
this.group.showErrors();
|
|
747
1145
|
if (status == "VALID") {
|
|
748
1146
|
resolve(null);
|
|
749
1147
|
return;
|
|
@@ -754,172 +1152,547 @@ class DynamicBaseFormComponent extends DynamicFormComponent {
|
|
|
754
1152
|
});
|
|
755
1153
|
}
|
|
756
1154
|
serialize(validate) {
|
|
757
|
-
return
|
|
758
|
-
|
|
759
|
-
|
|
1155
|
+
return new Promise((resolve, reject) => {
|
|
1156
|
+
const serialize = () => {
|
|
1157
|
+
this.group.serialize().then(resolve);
|
|
1158
|
+
};
|
|
760
1159
|
if (validate) {
|
|
761
|
-
|
|
1160
|
+
this.validate().then(serialize, reject);
|
|
1161
|
+
return;
|
|
762
1162
|
}
|
|
763
|
-
|
|
1163
|
+
serialize();
|
|
764
1164
|
});
|
|
765
1165
|
}
|
|
1166
|
+
check() {
|
|
1167
|
+
return this.group.check();
|
|
1168
|
+
}
|
|
1169
|
+
getControl(id) {
|
|
1170
|
+
return this.group.getControl(id);
|
|
1171
|
+
}
|
|
766
1172
|
}
|
|
767
|
-
|
|
1173
|
+
DynamicFormComponent.decorators = [
|
|
768
1174
|
{ type: Component, args: [{
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
1175
|
+
moduleId: module.id,
|
|
1176
|
+
selector: "dynamic-form, [dynamic-form]",
|
|
1177
|
+
template: "<ng-template #defaultFieldSetTemplate let-id=\"id\" let-controls=\"controls\" let-fieldSet=\"fieldSet\">\r\n <div [ngClass]=\"['form-fields', 'form-fields-' + id, fieldSet.classes]\">\r\n <ng-container [ngxTemplateOutlet]=\"setPrefixTemplates[fieldSet.id]\" [context]=\"fieldSet\"></ng-container>\r\n <div *ngIf=\"fieldSet.title\" [ngClass]=\"['form-title', fieldSet.titleClasses || '']\">\r\n {{ group.prefix + fieldSet.title | translate }}\r\n </div>\r\n <ng-template #subControls>\r\n <ng-container *ngFor=\"let control of controls\" [form-group]=\"control\" [visible]=\"control.visible\" [form]=\"this\">\r\n\r\n </ng-container>\r\n </ng-template>\r\n <div *ngIf=\"fieldSet.setClasses; else subControls\" [ngClass]=\"fieldSet.setClasses\">\r\n <div *ngIf=\"fieldSet.controlClasses; else subControls\" [ngClass]=\"fieldSet.controlClasses\">\r\n <ng-container [ngTemplateOutlet]=\"subControls\"></ng-container>\r\n </div>\r\n </div>\r\n <ng-container [ngxTemplateOutlet]=\"setSuffixTemplates[fieldSet.id]\" [context]=\"fieldSet\"></ng-container>\r\n </div>\r\n</ng-template>\r\n\r\n<ng-template #fieldSetsTemplate>\r\n <ng-container *ngFor=\"let fs of formControls | groupBy:'data.fieldSet'\"\r\n [ngxTemplateOutlet]=\"fieldSetTemplate || defaultFieldSetTemplate\"\r\n [context]=\"{form: this, id: fs.group, controls: fs.items, fieldSet: group.formFields[fs.group] || defaultFieldSet}\">\r\n </ng-container>\r\n</ng-template>\r\n<ng-template #defaultWrapperTemplate let-form=\"form\" let-fieldSetsTemplate=\"fieldSetsTemplate\">\r\n <ng-container [ngTemplateOutlet]=\"prefixTemplate\"\r\n [ngTemplateOutletContext]=\"{form: form, fieldSetsTemplate: fieldSetsTemplate}\"></ng-container>\r\n <form class=\"dynamic-form\" [ngClass]=\"form.classes || ''\" [formGroup]=\"group\" (submit)=\"onFormSubmit()\">\r\n <ng-container [ngTemplateOutlet]=\"fieldSetsTemplate\"></ng-container>\r\n <ng-content></ng-content>\r\n <div *ngIf=\"form.status == 'PENDING'\" class=\"dynamic-form-validator\">\r\n {{ group.prefix + 'message.pending' | translate }}\r\n </div>\r\n <button [ngStyle]=\"{display: 'none'}\">Submit</button>\r\n </form>\r\n <ng-container [ngTemplateOutlet]=\"suffixTemplate\"\r\n [ngTemplateOutletContext]=\"{form: form, fieldSetsTemplate: fieldSetsTemplate}\"></ng-container>\r\n</ng-template>\r\n<ng-template #loadingTemplate>\r\n <div *ngIf=\"status == 'LOADING'\" class=\"dynamic-form-loader\">\r\n {{ group.prefix + 'message.loading' | translate }}\r\n </div>\r\n</ng-template>\r\n<ng-container [ngTemplateOutlet]=\"wrapperTemplate || defaultWrapperTemplate\"\r\n [ngTemplateOutletContext]=\"{form: this, fieldSetsTemplate: fieldSetsTemplate}\"\r\n *ngIf=\"status !== 'LOADING'; else loadingTemplate\">\r\n</ng-container>\r\n",
|
|
1178
|
+
providers: [{ provide: DynamicFormBaseComponent, useExisting: DynamicFormComponent }]
|
|
772
1179
|
},] }
|
|
773
1180
|
];
|
|
774
|
-
|
|
775
|
-
{ type: DynamicFormService, decorators: [{ type: Inject, args: [DynamicFormService,] }] },
|
|
776
|
-
{ type: EventsService, decorators: [{ type: Inject, args: [EventsService,] }] },
|
|
1181
|
+
DynamicFormComponent.ctorParameters = () => [
|
|
777
1182
|
{ type: ChangeDetectorRef },
|
|
778
|
-
{ type:
|
|
1183
|
+
{ type: DynamicFormService }
|
|
779
1184
|
];
|
|
780
|
-
|
|
1185
|
+
DynamicFormComponent.propDecorators = {
|
|
781
1186
|
group: [{ type: Input }],
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
change: [{ type: Output }],
|
|
787
|
-
focus: [{ type: Output }],
|
|
788
|
-
contentTemplates: [{ type: ContentChildren, args: [DynamicTemplateDirective,] }],
|
|
789
|
-
viewTemplates: [{ type: ViewChildren, args: [DynamicTemplateDirective,] }],
|
|
790
|
-
onStatusChange: [{ type: Output }],
|
|
791
|
-
onValueChange: [{ type: Output }],
|
|
792
|
-
onSubmit: [{ type: Output }],
|
|
793
|
-
ngForm: [{ type: ViewChild, args: [NgForm,] }]
|
|
1187
|
+
controls: [{ type: Input }],
|
|
1188
|
+
serializers: [{ type: Input }],
|
|
1189
|
+
fieldSets: [{ type: Input }],
|
|
1190
|
+
data: [{ type: Input }]
|
|
794
1191
|
};
|
|
795
1192
|
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
this.
|
|
801
|
-
this.
|
|
802
|
-
this.
|
|
803
|
-
this.
|
|
804
|
-
this.componentService = componentService;
|
|
805
|
-
this.relationService = relationService;
|
|
806
|
-
this.context = null;
|
|
807
|
-
this.blur = new EventEmitter();
|
|
808
|
-
this.change = new EventEmitter();
|
|
809
|
-
this.focus = new EventEmitter();
|
|
810
|
-
}
|
|
811
|
-
get componentType() {
|
|
812
|
-
var _a;
|
|
813
|
-
return (_a = this.componentService.getCustomComponentType(this.model)) !== null && _a !== void 0 ? _a : this.getComponentType(this.model);
|
|
814
|
-
}
|
|
815
|
-
get startTemplate() {
|
|
816
|
-
return (this.model.type == DYNAMIC_FORM_CONTROL_TYPE_ARRAY)
|
|
817
|
-
? this.layoutService.getAlignedTemplate(this.model, this.templates, "ARRAY_START")
|
|
818
|
-
: this.layoutService.getStartTemplate(this.model, this.templates);
|
|
819
|
-
}
|
|
820
|
-
get endTemplate() {
|
|
821
|
-
return (this.model.type == DYNAMIC_FORM_CONTROL_TYPE_ARRAY)
|
|
822
|
-
? this.layoutService.getAlignedTemplate(this.model, this.templates, "ARRAY_END")
|
|
823
|
-
: this.layoutService.getEndTemplate(this.model, this.templates);
|
|
824
|
-
}
|
|
825
|
-
get formService() {
|
|
826
|
-
return this.form.formService;
|
|
1193
|
+
const statusPriority = ["LOADING", "PENDING", "DISABLED", "INVALID"];
|
|
1194
|
+
class DynamicFormsComponent extends DynamicFormBaseComponent {
|
|
1195
|
+
constructor(cdr, formService) {
|
|
1196
|
+
super(cdr, formService);
|
|
1197
|
+
this.formPrefixTemplates = {};
|
|
1198
|
+
this.formSuffixTemplates = {};
|
|
1199
|
+
this.innerFormPrefixTemplates = {};
|
|
1200
|
+
this.innerFormSuffixTemplates = {};
|
|
827
1201
|
}
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
1202
|
+
get status() {
|
|
1203
|
+
for (let i = 0; i < statusPriority.length; i++) {
|
|
1204
|
+
const status = statusPriority[i];
|
|
1205
|
+
if (this.checkForms(f => f.status == status))
|
|
1206
|
+
return status;
|
|
1207
|
+
}
|
|
1208
|
+
return "VALID";
|
|
1209
|
+
}
|
|
1210
|
+
// --- Lifecycle hooks
|
|
1211
|
+
ngAfterContentInit() {
|
|
1212
|
+
super.ngAfterContentInit();
|
|
1213
|
+
this.containerTemplate = this.containerTemplate || this.cContainerTemplate;
|
|
1214
|
+
this.formPrefixTemplates = this.filterTemplates(this.formPrefixTemplates, "formPrefix");
|
|
1215
|
+
this.formSuffixTemplates = this.filterTemplates(this.formSuffixTemplates, "formSuffix");
|
|
1216
|
+
this.innerFormPrefixTemplates = this.filterTemplates(this.innerFormPrefixTemplates, "innerFormPrefix");
|
|
1217
|
+
this.innerFormSuffixTemplates = this.filterTemplates(this.innerFormSuffixTemplates, "innerFormSuffix");
|
|
1218
|
+
}
|
|
1219
|
+
ngOnChanges(changes) {
|
|
1220
|
+
this.configs = this.createFormGroups(this.data);
|
|
1221
|
+
}
|
|
1222
|
+
// --- IDynamicFormBase ---
|
|
1223
|
+
validate(showErrors = true) {
|
|
1224
|
+
if (!this.forms)
|
|
1225
|
+
return Promise.reject(null);
|
|
1226
|
+
return Promise.all(this.forms.map(f => f.validate(showErrors)));
|
|
1227
|
+
}
|
|
1228
|
+
serialize(validate) {
|
|
1229
|
+
if (!this.forms)
|
|
1230
|
+
return validate ? Promise.reject(null) : Promise.resolve({});
|
|
1231
|
+
return new Promise((resolve, reject) => {
|
|
1232
|
+
const promises = this.forms.map(f => f.serialize(validate));
|
|
1233
|
+
Promise.all(promises).then(results => {
|
|
1234
|
+
let result = {};
|
|
1235
|
+
results.forEach((data, ix) => {
|
|
1236
|
+
const config = this.data[ix];
|
|
1237
|
+
let path = null;
|
|
1238
|
+
if (ObjectUtils.isArray(config.path) && config.path.length > 0) {
|
|
1239
|
+
path = config.path;
|
|
1240
|
+
}
|
|
1241
|
+
else if (ObjectUtils.isString(config.path) && config.path.length > 0) {
|
|
1242
|
+
path = config.path.split(".");
|
|
1243
|
+
}
|
|
1244
|
+
else if (ObjectUtils.isNumber(config.path)) {
|
|
1245
|
+
path = [config.path];
|
|
1246
|
+
}
|
|
1247
|
+
if (!path) {
|
|
1248
|
+
result = ObjectUtils.assign(result, data);
|
|
1249
|
+
return;
|
|
1250
|
+
}
|
|
1251
|
+
result = ObjectUtils.mapToPath(result, data, path.map(p => `${p}`));
|
|
1252
|
+
});
|
|
1253
|
+
resolve(result);
|
|
1254
|
+
}, reject);
|
|
1255
|
+
});
|
|
1256
|
+
}
|
|
1257
|
+
check() {
|
|
1258
|
+
if (!this.forms)
|
|
1259
|
+
return Promise.resolve(null);
|
|
1260
|
+
return Promise.all(this.forms.map(t => t.check()));
|
|
1261
|
+
}
|
|
1262
|
+
getControl(id) {
|
|
1263
|
+
return this.getFromValue(f => f.getControl(id));
|
|
1264
|
+
}
|
|
1265
|
+
checkForms(check) {
|
|
1266
|
+
this.cdr.detectChanges();
|
|
1267
|
+
if (!this.forms)
|
|
1268
|
+
return false;
|
|
1269
|
+
return ObjectUtils.isDefined(this.forms.find(check));
|
|
1270
|
+
}
|
|
1271
|
+
getFromValue(check) {
|
|
1272
|
+
if (!this.forms)
|
|
1273
|
+
return null;
|
|
1274
|
+
let value = null;
|
|
1275
|
+
this.forms.find(f => {
|
|
1276
|
+
value = check(f);
|
|
1277
|
+
return ObjectUtils.isDefined(value);
|
|
1278
|
+
});
|
|
1279
|
+
return value;
|
|
1280
|
+
}
|
|
1281
|
+
createFormGroups(configs) {
|
|
1282
|
+
return (configs || []).map((c) => {
|
|
1283
|
+
if (c.multi)
|
|
1284
|
+
return c;
|
|
1285
|
+
const config = c;
|
|
1286
|
+
const group = new DynamicFormGroup(this, {
|
|
1287
|
+
id: config.id || UniqueUtils.uuid(),
|
|
1288
|
+
type: "model",
|
|
1289
|
+
data: config.controlData
|
|
1290
|
+
});
|
|
1291
|
+
config.group = group;
|
|
1292
|
+
config.name = config.name || this.name;
|
|
1293
|
+
group.setup(config.data, config);
|
|
1294
|
+
group.reloadControls();
|
|
1295
|
+
return config;
|
|
1296
|
+
});
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
DynamicFormsComponent.decorators = [
|
|
1300
|
+
{ type: Component, args: [{
|
|
1301
|
+
moduleId: module.id,
|
|
1302
|
+
selector: "dynamic-forms, [dynamic-forms]",
|
|
1303
|
+
template: "<ng-template #configTemplate let-formTemplate=\"formTemplate\" let-form=\"form\" let-config=\"config\" let-configTemplate>\r\n <div [ngClass]=\"config.classes || ''\">\r\n <ng-container [ngTemplateOutlet]=\"formPrefixTemplates[config.id]\"\r\n [ngTemplateOutletContext]=\"{config: config, form: form}\"></ng-container>\r\n <ng-template #singleFormTemplate>\r\n <div dynamic-form\r\n [hidden]=\"!config.group?.visible\"\r\n [ngClass]=\"config.formClasses || ''\"\r\n [name]=\"config.name || form.name\"\r\n [readonly]=\"form.readonly\"\r\n [updateOn]=\"form.updateOn\"\r\n [classes]=\"config.innerFormClasses\"\r\n [parent]=\"form\"\r\n\r\n [wrapperTemplate]=\"form.wrapperTemplate\"\r\n [fieldSetTemplate]=\"form.fieldSetTemplate\"\r\n [controlTemplates]=\"form.controlTemplates\"\r\n\r\n [controlTemplate]=\"form.controlTemplate\"\r\n [labelTemplates]=\"form.labelTemplates\"\r\n [inputTemplates]=\"form.inputTemplates\"\r\n [prefixTemplates]=\"form.prefixTemplates\"\r\n [suffixTemplates]=\"form.suffixTemplates\"\r\n [setPrefixTemplates]=\"form.setPrefixTemplates\"\r\n [setSuffixTemplates]=\"form.setSuffixTemplates\"\r\n\r\n [group]=\"config.group\"\r\n [fieldSets]=\"config.fieldSets\">\r\n <ng-template #prefixTemplate let-subForm=\"form\">\r\n <ng-container [ngTemplateOutlet]=\"form.innerFormPrefixTemplates[config.id]\"\r\n [ngTemplateOutletContext]=\"{config: config, form: subForm}\"></ng-container>\r\n </ng-template>\r\n <ng-template #suffixTemplate let-subForm=\"form\">\r\n <ng-container [ngTemplateOutlet]=\"form.innerFormSuffixTemplates[config.id]\"\r\n [ngTemplateOutletContext]=\"{config: config, form: subForm}\"></ng-container>\r\n </ng-template>\r\n </div>\r\n </ng-template>\r\n <div dynamic-forms\r\n [ngClass]=\"config.formClasses || ''\"\r\n [name]=\"config.name || name\"\r\n [readonly]=\"form.readonly\"\r\n [updateOn]=\"form.updateOn\"\r\n [classes]=\"config.innerFormClasses\"\r\n [parent]=\"form\"\r\n\r\n [wrapperTemplate]=\"form.wrapperTemplate\"\r\n [fieldSetTemplate]=\"form.fieldSetTemplate\"\r\n [controlTemplates]=\"form.controlTemplates\"\r\n\r\n [controlTemplate]=\"form.controlTemplate\"\r\n [labelTemplates]=\"form.labelTemplates\"\r\n [inputTemplates]=\"form.inputTemplates\"\r\n [prefixTemplates]=\"form.prefixTemplates\"\r\n [suffixTemplates]=\"form.suffixTemplates\"\r\n [setPrefixTemplates]=\"form.setPrefixTemplates\"\r\n [setSuffixTemplates]=\"form.setSuffixTemplates\"\r\n\r\n [data]=\"config.data\"\r\n [containerTemplate]=\"form.containerTemplate\"\r\n [formPrefixTemplates]=\"form.formPrefixTemplates\"\r\n [formSuffixTemplates]=\"form.formSuffixTemplates\"\r\n [innerFormPrefixTemplates]=\"form.innerFormPrefixTemplates\"\r\n [innerFormSuffixTemplates]=\"form.innerFormSuffixTemplates\"\r\n\r\n *ngIf=\"config.multi; else singleFormTemplate\">\r\n <ng-template #prefixTemplate let-subForm=\"form\">\r\n <ng-container [ngTemplateOutlet]=\"form.innerFormPrefixTemplates[config.id]\"\r\n [ngTemplateOutletContext]=\"{config: config, form: subForm}\"></ng-container>\r\n </ng-template>\r\n <ng-template #suffixTemplate let-subForm=\"form\">\r\n <ng-container [ngTemplateOutlet]=\"form.innerFormSuffixTemplates[config.id]\"\r\n [ngTemplateOutletContext]=\"{config: config, form: subForm}\"></ng-container>\r\n </ng-template>\r\n </div>\r\n <ng-container [ngTemplateOutlet]=\"formSuffixTemplates[config.id]\"\r\n [ngTemplateOutletContext]=\"{config: config, form: form}\"></ng-container>\r\n </div>\r\n</ng-template>\r\n<ng-template let-form=\"form\" let-configTemplate=\"configTemplate\" #defaultContainerTemplate>\r\n <div class=\"dynamic-forms\" [ngClass]=\"classes || ''\">\r\n <ng-container *ngFor=\"let config of form.configs\"\r\n [ngTemplateOutlet]=\"configTemplate\"\r\n [ngTemplateOutletContext]=\"{form: form, config: config}\"></ng-container>\r\n <ng-content></ng-content>\r\n </div>\r\n</ng-template>\r\n<ng-container [ngTemplateOutlet]=\"prefixTemplate\"\r\n [ngTemplateOutletContext]=\"{form: this}\"></ng-container>\r\n<ng-container [ngTemplateOutlet]=\"containerTemplate || defaultContainerTemplate\"\r\n [ngTemplateOutletContext]=\"{form: this, configTemplate: configTemplate, defaultContainerTemplate: defaultContainerTemplate}\">\r\n</ng-container>\r\n<ng-container [ngTemplateOutlet]=\"suffixTemplate\"\r\n [ngTemplateOutletContext]=\"{form: this}\"></ng-container>\r\n",
|
|
1304
|
+
providers: [{ provide: DynamicFormBaseComponent, useExisting: DynamicFormsComponent }]
|
|
1305
|
+
},] }
|
|
1306
|
+
];
|
|
1307
|
+
DynamicFormsComponent.ctorParameters = () => [
|
|
1308
|
+
{ type: ChangeDetectorRef },
|
|
1309
|
+
{ type: DynamicFormService }
|
|
1310
|
+
];
|
|
1311
|
+
DynamicFormsComponent.propDecorators = {
|
|
1312
|
+
data: [{ type: Input }],
|
|
1313
|
+
containerTemplate: [{ type: Input }],
|
|
1314
|
+
formPrefixTemplates: [{ type: Input }],
|
|
1315
|
+
formSuffixTemplates: [{ type: Input }],
|
|
1316
|
+
innerFormPrefixTemplates: [{ type: Input }],
|
|
1317
|
+
innerFormSuffixTemplates: [{ type: Input }],
|
|
1318
|
+
cContainerTemplate: [{ type: ContentChild, args: ["containerTemplate",] }],
|
|
1319
|
+
forms: [{ type: ViewChildren, args: [DynamicFormBaseComponent,] }]
|
|
1320
|
+
};
|
|
1321
|
+
|
|
1322
|
+
class DynamicFormGroupComponent {
|
|
1323
|
+
get classes() {
|
|
1324
|
+
if (!this.control)
|
|
1325
|
+
return "form-group";
|
|
1326
|
+
return ["form-group", "form-group-" + this.control.id, this.control.data.classes, this.control.errors && this.control.touched ? "form-group-invalid" : ""].join(" ");
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
DynamicFormGroupComponent.decorators = [
|
|
1330
|
+
{ type: Component, args: [{
|
|
1331
|
+
moduleId: module.id,
|
|
1332
|
+
selector: "div[dynamic-form-group]",
|
|
1333
|
+
template: "<ng-template #labelTemplate>\r\n <label [ngClass]=\"'control-label control-label-' + control.data.labelAlign\" [attr.for]=\"control.formId\">\r\n {{ control.label | translate: control.model }}\r\n </label>\r\n</ng-template>\r\n<ng-template #errorTemplate>\r\n <div class=\"error-message\" *ngIf=\"control.errors && control.touched\">\r\n <span class=\"help-block\" *ngFor=\"let error of control.errors | entries\">\r\n {{ error.key | translate: error.value }}\r\n </span>\r\n </div>\r\n</ng-template>\r\n<ng-template #inputTemplate let-control=\"control\">\r\n <ng-container [form-control]=\"control\"></ng-container>\r\n</ng-template>\r\n<ng-template #defaultControlTemplate\r\n let-context\r\n let-control=\"control\"\r\n let-data=\"control.data\"\r\n let-labelTemplate=\"labelTemplate\"\r\n let-inputTemplate=\"inputTemplate\"\r\n let-prefixTemplate=\"prefixTemplate\"\r\n let-suffixTemplate=\"suffixTemplate\"\r\n let-errorTemplate=\"errorTemplate\">\r\n <ng-container [ngTemplateOutlet]=\"prefixTemplate\"\r\n [ngTemplateOutletContext]=\"context\"></ng-container>\r\n <ng-container *ngIf=\"control.label && data.labelAlign == 'left'\"\r\n [ngTemplateOutlet]=\"labelTemplate\"\r\n [ngTemplateOutletContext]=\"context\">\r\n </ng-container>\r\n <ng-container [ngTemplateOutlet]=\"inputTemplate\"\r\n [ngTemplateOutletContext]=\"context\"></ng-container>\r\n <ng-container *ngIf=\"control.label && data.labelAlign == 'right'\"\r\n [ngTemplateOutlet]=\"labelTemplate\"\r\n [ngTemplateOutletContext]=\"context\">\r\n </ng-container>\r\n <ng-container [ngTemplateOutlet]=\"suffixTemplate\"\r\n [ngTemplateOutletContext]=\"context\"></ng-container>\r\n <ng-container [ngTemplateOutlet]=\"errorTemplate\"\r\n [ngTemplateOutletContext]=\"context\"></ng-container>\r\n</ng-template>\r\n\r\n<ng-container [ngxTemplateOutlet]=\"form.controlTemplates[control.id] || form.controlTemplate || defaultControlTemplate\"\r\n [context]=\"{\r\n control: control,\r\n labelTemplate: form.labelTemplates[control.id] || labelTemplate,\r\n inputTemplate: form.inputTemplates[control.id] || inputTemplate,\r\n prefixTemplate: form.prefixTemplates[control.id],\r\n suffixTemplate: form.suffixTemplates[control.id],\r\n errorTemplate: errorTemplate\r\n }\">\r\n</ng-container>\r\n"
|
|
1334
|
+
},] }
|
|
1335
|
+
];
|
|
1336
|
+
DynamicFormGroupComponent.propDecorators = {
|
|
1337
|
+
classes: [{ type: HostBinding, args: ["class",] }]
|
|
1338
|
+
};
|
|
1339
|
+
|
|
1340
|
+
class DynamicFormFileComponent extends FormControlComponent {
|
|
1341
|
+
constructor(api, toaster) {
|
|
1342
|
+
super();
|
|
1343
|
+
this.api = api;
|
|
1344
|
+
this.toaster = toaster;
|
|
1345
|
+
this.fileImageCache = [];
|
|
1346
|
+
}
|
|
1347
|
+
// Acceptor for provider
|
|
1348
|
+
static acceptor(control) {
|
|
1349
|
+
return control.type == "file";
|
|
1350
|
+
}
|
|
1351
|
+
// Loader for provider
|
|
1352
|
+
static loader() {
|
|
1353
|
+
return Promise.resolve();
|
|
1354
|
+
}
|
|
1355
|
+
onSelect(input) {
|
|
1356
|
+
this.processFiles(input.files);
|
|
1357
|
+
input.value = "";
|
|
1358
|
+
}
|
|
1359
|
+
processFiles(fileList) {
|
|
1360
|
+
const files = [];
|
|
1361
|
+
const accept = this.data.accept;
|
|
1362
|
+
const types = ObjectUtils.isString(accept) && accept.length > 0 ? accept.toLowerCase().split(",") : null;
|
|
1363
|
+
if (fileList.length == 0)
|
|
1364
|
+
return;
|
|
1365
|
+
for (let i = 0; i < fileList.length; i++) {
|
|
1366
|
+
const file = fileList.item(i);
|
|
1367
|
+
const type = file.type.toLowerCase();
|
|
1368
|
+
const ext = FileUtils.getExtension(file);
|
|
1369
|
+
if (types && !ArrayUtils.has(types, type, ext))
|
|
1370
|
+
continue;
|
|
1371
|
+
files.push(file);
|
|
1372
|
+
}
|
|
1373
|
+
if (files.length == 0) {
|
|
1374
|
+
this.toaster.error("message.error.wrong-files");
|
|
1375
|
+
return;
|
|
1376
|
+
}
|
|
1377
|
+
this.upload(files);
|
|
1378
|
+
}
|
|
1379
|
+
upload(files) {
|
|
1380
|
+
const single = !this.data.multi;
|
|
1381
|
+
if (single)
|
|
1382
|
+
files.length = Math.min(files.length, 1);
|
|
1383
|
+
const promises = [];
|
|
1384
|
+
files.forEach((file, ix) => {
|
|
1385
|
+
if (this.data.asDataUrl) {
|
|
1386
|
+
promises.push(FileUtils.readFileAsDataURL(file));
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
if (this.data.asFile) {
|
|
1390
|
+
promises.push(Promise.resolve(file));
|
|
831
1391
|
return;
|
|
832
|
-
|
|
833
|
-
this.
|
|
1392
|
+
}
|
|
1393
|
+
promises.push(this.api.upload(this.data.uploadUrl, this.data.createUploadData(file), console.log, this.data.uploadOptions).then(asset => asset._id || asset, () => null));
|
|
1394
|
+
});
|
|
1395
|
+
Promise.all(promises).then(assets => {
|
|
1396
|
+
if (single) {
|
|
1397
|
+
this.control.setValue(assets[0]);
|
|
1398
|
+
return;
|
|
1399
|
+
}
|
|
1400
|
+
const current = this.value || [];
|
|
1401
|
+
this.control.setValue(current.concat(assets.filter(t => !!t)));
|
|
834
1402
|
});
|
|
835
1403
|
}
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
var _a;
|
|
842
|
-
super.createFormControlComponent();
|
|
843
|
-
const component = (_a = this.componentRef) === null || _a === void 0 ? void 0 : _a.instance;
|
|
844
|
-
if (!component || !ObjectUtils.isFunction(component.onCreated))
|
|
1404
|
+
delete(index) {
|
|
1405
|
+
if (this.data.multi) {
|
|
1406
|
+
const current = Array.from(this.value || []);
|
|
1407
|
+
current.splice(index, 1);
|
|
1408
|
+
this.control.setValue(current);
|
|
845
1409
|
return;
|
|
846
|
-
|
|
1410
|
+
}
|
|
1411
|
+
this.control.setValue(null);
|
|
847
1412
|
}
|
|
848
|
-
|
|
849
|
-
return
|
|
1413
|
+
getUrl(image) {
|
|
1414
|
+
return `url('${this.getImgUrl(image)}')`;
|
|
1415
|
+
}
|
|
1416
|
+
getImgUrl(image) {
|
|
1417
|
+
if (ObjectUtils.isBlob(image)) {
|
|
1418
|
+
let cache = this.fileImageCache.find(t => t.file == image);
|
|
1419
|
+
if (!cache) {
|
|
1420
|
+
cache = { file: image, url: URL.createObjectURL(image) };
|
|
1421
|
+
this.fileImageCache.push(cache);
|
|
1422
|
+
}
|
|
1423
|
+
return cache.url;
|
|
1424
|
+
}
|
|
1425
|
+
const url = !image ? null : image.imageUrl || image;
|
|
1426
|
+
if (!ObjectUtils.isString(url))
|
|
1427
|
+
return null;
|
|
1428
|
+
if (url.startsWith("data:"))
|
|
1429
|
+
return url;
|
|
1430
|
+
if (!this.data.baseUrl) {
|
|
1431
|
+
const subUrl = url.startsWith("/") ? url.substr(1) : url;
|
|
1432
|
+
return this.api.url(subUrl);
|
|
1433
|
+
}
|
|
1434
|
+
return this.api.url(`${this.data.baseUrl}${url}`);
|
|
850
1435
|
}
|
|
851
1436
|
}
|
|
852
|
-
|
|
1437
|
+
DynamicFormFileComponent.decorators = [
|
|
853
1438
|
{ type: Component, args: [{
|
|
854
|
-
selector: "dynamic-
|
|
855
|
-
template: "",
|
|
856
|
-
|
|
1439
|
+
selector: "dynamic-form-file",
|
|
1440
|
+
template: "<div class=\"upload\">\r\n <input type=\"file\" (change)=\"onSelect($event.target)\" [attr.accept]=\"data.accept\" multiple=\"multiple\"/>\r\n <ul class=\"images\" *ngIf=\"!data.multi\">\r\n <li class=\"image\" *ngIf=\"value\" [ngStyle]=\"{backgroundImage: getUrl(value)}\">\r\n <a class=\"btn btn-delete\" (click)=\"delete()\"></a>\r\n </li>\r\n </ul>\r\n <ul class=\"images\" *ngIf=\"data.multi\">\r\n <li class=\"image\" *ngFor=\"let image of value; let i = index\" [ngStyle]=\"{backgroundImage: getUrl(image)}\">\r\n <a class=\"btn btn-delete\" (click)=\"delete(i)\"></a>\r\n </li>\r\n </ul>\r\n</div>\r\n",
|
|
1441
|
+
styles: [".upload{display:inline-block}.upload ul{display:inline-flex;list-style:none;margin:10px 0 0;padding:0}.upload ul li{height:100px;width:100px;background:repeating-linear-gradient(45deg,gray,gray 10px,lightgray 10px,lightgray 20px) center center;background-size:cover;border:1px gray solid;margin-right:5px;position:relative}.upload .btn-delete{background:linear-gradient(to bottom,#c8607a,#a64d5a);border-color:#a64d5a;color:#fff;position:absolute;padding:0;right:5px;top:5px;width:20px;height:20px}.upload .btn-delete:before{color:#fff;display:block;position:absolute;top:0;right:6px;content:\"x\"}\n"]
|
|
857
1442
|
},] }
|
|
858
1443
|
];
|
|
859
|
-
|
|
860
|
-
{ type:
|
|
861
|
-
{ type:
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
{
|
|
866
|
-
|
|
1444
|
+
DynamicFormFileComponent.ctorParameters = () => [
|
|
1445
|
+
{ type: ApiService },
|
|
1446
|
+
{ type: undefined, decorators: [{ type: Inject, args: [TOASTER_SERVICE,] }] }
|
|
1447
|
+
];
|
|
1448
|
+
|
|
1449
|
+
class DynamicFormInputComponent extends FormControlComponent {
|
|
1450
|
+
constructor(language) {
|
|
1451
|
+
super();
|
|
1452
|
+
this.language = language;
|
|
1453
|
+
}
|
|
1454
|
+
// Acceptor for provider
|
|
1455
|
+
static acceptor(control) {
|
|
1456
|
+
return control.type == "input";
|
|
1457
|
+
}
|
|
1458
|
+
// Loader for provider
|
|
1459
|
+
static loader() {
|
|
1460
|
+
return Promise.resolve();
|
|
1461
|
+
}
|
|
1462
|
+
get isChecked() {
|
|
1463
|
+
return this.data.type == "checkbox" && this.value;
|
|
1464
|
+
}
|
|
1465
|
+
onDateChange(value) {
|
|
1466
|
+
const date = new Date(value);
|
|
1467
|
+
const dateValue = date.valueOf();
|
|
1468
|
+
if (isNaN(dateValue) || dateValue < -30610224000000)
|
|
1469
|
+
return;
|
|
1470
|
+
this.control.setValue(date);
|
|
1471
|
+
}
|
|
1472
|
+
onTextChange(value) {
|
|
1473
|
+
if (!this.data.useLanguage) {
|
|
1474
|
+
this.control.setValue(value);
|
|
1475
|
+
return;
|
|
1476
|
+
}
|
|
1477
|
+
const translations = ObjectUtils.isArray(this.value) ? Array.from(this.value) : [];
|
|
1478
|
+
const translation = translations.find(t => t.lang == this.language.editLanguage);
|
|
1479
|
+
if (translation) {
|
|
1480
|
+
translation.translation = value;
|
|
1481
|
+
}
|
|
1482
|
+
else {
|
|
1483
|
+
translations.push({
|
|
1484
|
+
lang: this.language.editLanguage,
|
|
1485
|
+
translation: value
|
|
1486
|
+
});
|
|
1487
|
+
}
|
|
1488
|
+
this.control.setValue(translations);
|
|
1489
|
+
}
|
|
1490
|
+
onNumberBlur() {
|
|
1491
|
+
const value = this.value;
|
|
1492
|
+
if (ObjectUtils.isNumber(this.data.max) && this.data.max < value) {
|
|
1493
|
+
this.control.setValue(this.data.max);
|
|
1494
|
+
}
|
|
1495
|
+
else if (ObjectUtils.isNumber(this.data.min) && this.data.min > value) {
|
|
1496
|
+
this.control.setValue(this.data.min);
|
|
1497
|
+
}
|
|
1498
|
+
this.control.onBlur();
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
DynamicFormInputComponent.decorators = [
|
|
1502
|
+
{ type: Component, args: [{
|
|
1503
|
+
moduleId: module.id,
|
|
1504
|
+
selector: "dynamic-form-input",
|
|
1505
|
+
template: "<ng-container [ngSwitch]=\"data.type\">\r\n <ng-container *ngSwitchCase=\"'textarea'\">\r\n <textarea class=\"form-control\"\r\n rows=\"5\"\r\n [attr.autocomplete]=\"data.autocomplete\"\r\n [id]=\"control.formId\"\r\n [name]=\"control.formId\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled\"\r\n [ngModel]=\"value\"\r\n (ngModelChange)=\"control.setValue($event)\"\r\n (blur)=\"control.onBlur()\"\r\n (focus)=\"control.onFocus()\">{{ data.placeholder | translate }}</textarea>\r\n </ng-container>\r\n <ng-container *ngSwitchCase=\"'date'\">\r\n <input class=\"form-control\"\r\n type=\"date\"\r\n [attr.autocomplete]=\"data.autocomplete\"\r\n [id]=\"control.formId\"\r\n [name]=\"control.formId\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled\"\r\n [ngModel]=\"value | date: 'y-MM-dd'\"\r\n (ngModelChange)=\"onDateChange($event)\"\r\n (blur)=\"control.onBlur()\"\r\n (focus)=\"control.onFocus()\"/>\r\n </ng-container>\r\n <ng-container *ngSwitchCase=\"'number'\">\r\n <input class=\"form-control\"\r\n type=\"number\"\r\n [attr.autocomplete]=\"data.autocomplete\"\r\n [min]=\"data.min\"\r\n [max]=\"data.max\"\r\n [step]=\"data.step\"\r\n [id]=\"control.formId\"\r\n [name]=\"control.formId\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled\"\r\n [ngModel]=\"value\"\r\n (ngModelChange)=\"control.setValue($event)\"\r\n (blur)=\"onNumberBlur()\"\r\n (focus)=\"control.onFocus()\"/>\r\n </ng-container>\r\n <ng-container *ngSwitchCase=\"'checkbox'\">\r\n <input class=\"form-control\"\r\n type=\"checkbox\"\r\n [id]=\"control.formId\"\r\n [name]=\"control.formId\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled\"\r\n [ngModel]=\"value\"\r\n (ngModelChange)=\"control.setValue($event)\"\r\n (blur)=\"control.onBlur()\"\r\n (focus)=\"control.onFocus()\"/>\r\n </ng-container>\r\n <ng-container *ngSwitchCase=\"'text'\">\r\n <input class=\"form-control\"\r\n type=\"text\"\r\n [attr.autocomplete]=\"data.autocomplete\"\r\n [minlength]=\"data.min\"\r\n [maxlength]=\"data.max\"\r\n [placeholder]=\"data.placeholder | translate\"\r\n [id]=\"control.formId\"\r\n [name]=\"control.formId\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled\"\r\n [ngModel]=\"data.useLanguage ? (value | translate) : value\"\r\n (ngModelChange)=\"onTextChange($event)\"\r\n (blur)=\"control.onBlur()\"\r\n (focus)=\"control.onFocus()\"/>\r\n </ng-container>\r\n <ng-container *ngSwitchDefault>\r\n <input class=\"form-control\"\r\n [attr.autocomplete]=\"data.autocomplete\"\r\n [minlength]=\"data.min\"\r\n [maxlength]=\"data.max\"\r\n [placeholder]=\"data.placeholder | translate\"\r\n [type]=\"data.type\"\r\n [id]=\"control.formId\"\r\n [name]=\"control.formId\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled\"\r\n [ngModel]=\"value\"\r\n (ngModelChange)=\"control.setValue($event)\"\r\n (blur)=\"control.onBlur()\"\r\n (focus)=\"control.onFocus()\"/>\r\n </ng-container>\r\n</ng-container>\r\n"
|
|
1506
|
+
},] }
|
|
867
1507
|
];
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
hostClass: [{ type: Input }],
|
|
874
|
-
inputTemplateList: [{ type: Input, args: ["templates",] }],
|
|
875
|
-
layout: [{ type: Input }],
|
|
876
|
-
model: [{ type: Input }],
|
|
877
|
-
blur: [{ type: Output }],
|
|
878
|
-
change: [{ type: Output }],
|
|
879
|
-
focus: [{ type: Output }],
|
|
880
|
-
componentViewContainerRef: [{ type: ViewChild, args: ["componentViewContainer", { read: ViewContainerRef, static: true },] }]
|
|
1508
|
+
DynamicFormInputComponent.ctorParameters = () => [
|
|
1509
|
+
{ type: undefined, decorators: [{ type: Inject, args: [LANGUAGE_SERVICE,] }] }
|
|
1510
|
+
];
|
|
1511
|
+
DynamicFormInputComponent.propDecorators = {
|
|
1512
|
+
isChecked: [{ type: HostBinding, args: ["class.checked",] }]
|
|
881
1513
|
};
|
|
882
1514
|
|
|
883
|
-
class
|
|
884
|
-
|
|
885
|
-
|
|
1515
|
+
class DynamicFormSelectComponent extends FormControlComponent {
|
|
1516
|
+
// Acceptor for provider
|
|
1517
|
+
static acceptor(control) {
|
|
1518
|
+
return control.type == "select";
|
|
1519
|
+
}
|
|
1520
|
+
// Loader for provider
|
|
1521
|
+
static loader(control) {
|
|
1522
|
+
const data = control.getData();
|
|
1523
|
+
if (data.type == "radio" && data.multi) {
|
|
1524
|
+
return Promise.reject("Radio group doesn't support multi select!");
|
|
1525
|
+
}
|
|
1526
|
+
return new Promise(resolve => {
|
|
1527
|
+
const getOptions = ReflectUtils.resolve(data.options, control.form.injector);
|
|
1528
|
+
getOptions(control).then(options => {
|
|
1529
|
+
if (data.emptyOption)
|
|
1530
|
+
options.unshift({ id: null, label: "" });
|
|
1531
|
+
control.meta.options = options;
|
|
1532
|
+
DynamicFormSelectComponent.fillOptions(control, options);
|
|
1533
|
+
resolve(options);
|
|
1534
|
+
});
|
|
1535
|
+
});
|
|
1536
|
+
}
|
|
1537
|
+
static fillOptions(control, options) {
|
|
1538
|
+
const data = control.getData();
|
|
1539
|
+
const selected = control.value;
|
|
1540
|
+
if (data.multi || options.length == 0 || options.findIndex(t => t.id == selected) >= 0)
|
|
1541
|
+
return;
|
|
1542
|
+
control.setValue(options[0].id);
|
|
1543
|
+
}
|
|
1544
|
+
onSelectChange(value) {
|
|
1545
|
+
const isArray = ObjectUtils.isArray(value);
|
|
1546
|
+
const current = this.value;
|
|
1547
|
+
if (this.data.multi) {
|
|
1548
|
+
if (isArray) {
|
|
1549
|
+
this.control.setValue(value);
|
|
1550
|
+
return;
|
|
1551
|
+
}
|
|
1552
|
+
if (ObjectUtils.isArray(current)) {
|
|
1553
|
+
this.control.setValue(current.indexOf(value) < 0
|
|
1554
|
+
? current.concat([value])
|
|
1555
|
+
: current.filter(c => c !== value));
|
|
1556
|
+
return;
|
|
1557
|
+
}
|
|
1558
|
+
this.control.setValue([value]);
|
|
1559
|
+
return;
|
|
1560
|
+
}
|
|
1561
|
+
if (isArray)
|
|
1562
|
+
value = value[0];
|
|
1563
|
+
if (current == value) {
|
|
1564
|
+
const option = this.meta.options.find(o => o.id !== value);
|
|
1565
|
+
value = option ? option.id : null;
|
|
1566
|
+
}
|
|
1567
|
+
this.control.setValue(value);
|
|
1568
|
+
}
|
|
1569
|
+
checkValue(option) {
|
|
1570
|
+
const value = this.value;
|
|
1571
|
+
return ObjectUtils.isArray(value) ? value.indexOf(option.id) >= 0 : option.id == value;
|
|
1572
|
+
}
|
|
1573
|
+
findOption(option, index, id) {
|
|
1574
|
+
return option.id == id;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
DynamicFormSelectComponent.decorators = [
|
|
1578
|
+
{ type: Component, args: [{
|
|
1579
|
+
moduleId: module.id,
|
|
1580
|
+
selector: "dynamic-form-select",
|
|
1581
|
+
template: "<ng-template #selectTemplate let-selected=\"selected\">\r\n <select class=\"form-control\"\r\n [multiple]=\"data.multi\"\r\n [id]=\"control.formId\"\r\n [name]=\"control.formId\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled\"\r\n [ngModel]=\"data.multi ? value : [value]\"\r\n (ngModelChange)=\"onSelectChange($event)\"\r\n (blur)=\"control.onBlur()\"\r\n (focus)=\"control.onFocus()\">\r\n <option *ngFor=\"let option of meta.options\" [value]=\"option.id\" [disabled]=\"option.selectable == false\">\r\n {{ option.label | translate }}\r\n </option>\r\n </select>\r\n <label class=\"form-control-description\" [attr.for]=\"control.formId\" *ngIf=\"!data.multi && selected?.description\">\r\n {{ selected?.description | translate }}\r\n </label>\r\n</ng-template>\r\n<ng-container [ngSwitch]=\"data.type\">\r\n <ng-container *ngSwitchCase=\"'radio'\">\r\n <ul class=\"radio-group\">\r\n <li *ngFor=\"let option of meta.options\" class=\"radio\">\r\n <label [ngClass]=\"{checked: value == option.id}\">\r\n <input type=\"radio\"\r\n [id]=\"control.formId + '-' + option.id\"\r\n [name]=\"control.formId + '-' + option.id\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled || option.selectable == false\"\r\n [value]=\"option.id\"\r\n [ngModel]=\"value\"\r\n (ngModelChange)=\"onSelectChange(option.id)\"\r\n (blur)=\"control.onBlur()\"\r\n (focus)=\"control.onFocus()\">\r\n {{ option.label | translate }}\r\n </label>\r\n </li>\r\n </ul>\r\n </ng-container>\r\n <ng-container *ngSwitchCase=\"'checkbox'\">\r\n <ul class=\"checkbox-group\">\r\n <li *ngFor=\"let option of meta.options\" class=\"checkbox\">\r\n <label [ngClass]=\"{checked: checkValue(option)}\">\r\n <input type=\"checkbox\"\r\n [id]=\"control.formId + '-' + option.id\"\r\n [name]=\"control.formId + '-' + option.id\"\r\n [ngClass]=\"{disabled: control.disabled}\"\r\n [disabled]=\"control.disabled || option.selectable == false\"\r\n [ngModel]=\"checkValue(option)\"\r\n (ngModelChange)=\"onSelectChange(option.id)\"\r\n (blur)=\"control.onBlur()\"\r\n (focus)=\"control.onFocus()\">\r\n {{ option.label | translate }}\r\n </label>\r\n </li>\r\n </ul>\r\n </ng-container>\r\n <ng-container *ngSwitchDefault [ngTemplateOutlet]=\"selectTemplate\" [ngTemplateOutletContext]=\"{selected: meta?.options | find:findOption:value}\">\r\n\r\n </ng-container>\r\n</ng-container>\r\n"
|
|
1582
|
+
},] }
|
|
1583
|
+
];
|
|
1584
|
+
|
|
1585
|
+
class DynamicFormStaticComponent extends FormControlComponent {
|
|
1586
|
+
// Acceptor for provider
|
|
1587
|
+
static acceptor(control) {
|
|
1588
|
+
return control.type == "static";
|
|
1589
|
+
}
|
|
1590
|
+
// Loader for provider
|
|
1591
|
+
static loader() {
|
|
1592
|
+
return Promise.resolve();
|
|
886
1593
|
}
|
|
887
1594
|
}
|
|
888
|
-
|
|
889
|
-
{ type:
|
|
1595
|
+
DynamicFormStaticComponent.decorators = [
|
|
1596
|
+
{ type: Component, args: [{
|
|
1597
|
+
moduleId: module.id,
|
|
1598
|
+
selector: "dynamic-form-static",
|
|
1599
|
+
template: "<unordered-list [listStyle]=\"data.style\" [ngClass]=\"{disabled: control.disabled}\"\r\n [data]=\"!data.properties ? {value: value} : data.properties | remap: value\">\r\n <ng-template [type]=\"!data.properties ? 'key' : null\" selector=\"level == 0\" let-item=\"item\"></ng-template>\r\n <ng-template type=\"value\" selector=\"valueType == 'date'\" let-item=\"item\">\r\n {{ item.value | date }}\r\n </ng-template>\r\n</unordered-list>\r\n"
|
|
1600
|
+
},] }
|
|
890
1601
|
];
|
|
891
1602
|
|
|
1603
|
+
class DynamicFormModelComponent extends FormControlComponent {
|
|
1604
|
+
// Acceptor for provider
|
|
1605
|
+
static acceptor(control) {
|
|
1606
|
+
return control.type == "model";
|
|
1607
|
+
}
|
|
1608
|
+
// Loader for provider
|
|
1609
|
+
static loader() {
|
|
1610
|
+
return Promise.resolve();
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
DynamicFormModelComponent.decorators = [
|
|
1614
|
+
{ type: Component, args: [{
|
|
1615
|
+
moduleId: module.id,
|
|
1616
|
+
selector: "dynamic-form-model",
|
|
1617
|
+
template: "<dynamic-form [name]=\"data.name || form.name\"\r\n [group]=\"control\"\r\n [data]=\"value\"\r\n [updateOn]=\"control.updateOn\"\r\n [parent]=\"form\"\r\n\r\n [fieldSetTemplate]=\"form.fieldSetTemplate\"\r\n [controlTemplates]=\"form.controlTemplates\"\r\n\r\n [controlTemplate]=\"form.controlTemplate\"\r\n [labelTemplates]=\"form.labelTemplates\"\r\n [inputTemplates]=\"form.inputTemplates\"\r\n [prefixTemplates]=\"form.prefixTemplates\"\r\n [suffixTemplates]=\"form.suffixTemplates\"\r\n [setPrefixTemplates]=\"form.setPrefixTemplates\"\r\n [setSuffixTemplates]=\"form.setSuffixTemplates\"\r\n\r\n #subForm>\r\n <ng-template #wrapperTemplate let-form=\"form\" let-fieldSetsTemplate=\"fieldSetsTemplate\">\r\n <ng-container [ngTemplateOutlet]=\"fieldSetsTemplate\"></ng-container>\r\n </ng-template>\r\n</dynamic-form>\r\n"
|
|
1618
|
+
},] }
|
|
1619
|
+
];
|
|
1620
|
+
DynamicFormModelComponent.propDecorators = {
|
|
1621
|
+
subForm: [{ type: ViewChild, args: ["subForm",] }]
|
|
1622
|
+
};
|
|
1623
|
+
|
|
1624
|
+
class DynamicFormGroupDirective {
|
|
1625
|
+
constructor(vcr, forms) {
|
|
1626
|
+
this.vcr = vcr;
|
|
1627
|
+
this.forms = forms;
|
|
1628
|
+
}
|
|
1629
|
+
get component() {
|
|
1630
|
+
return this.comp;
|
|
1631
|
+
}
|
|
1632
|
+
ngOnChanges(changes) {
|
|
1633
|
+
if (changes.control || changes.form || changes.visible) {
|
|
1634
|
+
if (!this.visible) {
|
|
1635
|
+
this.vcr.clear();
|
|
1636
|
+
this.comp = null;
|
|
1637
|
+
return;
|
|
1638
|
+
}
|
|
1639
|
+
this.comp = this.forms.createGroup(this.vcr);
|
|
1640
|
+
}
|
|
1641
|
+
if (!this.comp)
|
|
1642
|
+
return;
|
|
1643
|
+
this.comp.form = this.form;
|
|
1644
|
+
this.comp.control = this.control;
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
DynamicFormGroupDirective.decorators = [
|
|
1648
|
+
{ type: Directive, args: [{
|
|
1649
|
+
selector: "[form-group]",
|
|
1650
|
+
},] }
|
|
1651
|
+
];
|
|
1652
|
+
DynamicFormGroupDirective.ctorParameters = () => [
|
|
1653
|
+
{ type: ViewContainerRef },
|
|
1654
|
+
{ type: DynamicFormService }
|
|
1655
|
+
];
|
|
1656
|
+
DynamicFormGroupDirective.propDecorators = {
|
|
1657
|
+
control: [{ type: Input, args: ["form-group",] }],
|
|
1658
|
+
form: [{ type: Input }],
|
|
1659
|
+
visible: [{ type: Input }]
|
|
1660
|
+
};
|
|
1661
|
+
|
|
892
1662
|
// --- Components ---
|
|
893
1663
|
const components = [
|
|
894
|
-
|
|
895
|
-
|
|
1664
|
+
DynamicFormsComponent,
|
|
1665
|
+
DynamicFormComponent,
|
|
1666
|
+
DynamicFormGroupComponent,
|
|
1667
|
+
DynamicFormFileComponent,
|
|
1668
|
+
DynamicFormInputComponent,
|
|
1669
|
+
DynamicFormSelectComponent,
|
|
1670
|
+
DynamicFormStaticComponent,
|
|
1671
|
+
DynamicFormModelComponent
|
|
896
1672
|
];
|
|
897
1673
|
// --- Directives ---
|
|
898
1674
|
const directives = [
|
|
899
1675
|
AsyncSubmitDirective,
|
|
1676
|
+
DynamicFormControlDirective,
|
|
1677
|
+
DynamicFormGroupDirective,
|
|
1678
|
+
DynamicFormTemplateDirective
|
|
900
1679
|
];
|
|
901
1680
|
// --- Pipes ---
|
|
902
1681
|
const pipes = [];
|
|
903
|
-
const ɵ0$1 = validateJSON, ɵ1 = validateRequiredTranslation, ɵ2 = validatePhone, ɵ3 = new Map([
|
|
904
|
-
["validateJSON", validateJSON],
|
|
905
|
-
["validateRequiredTranslation", validateRequiredTranslation],
|
|
906
|
-
["validatePhone", validatePhone],
|
|
907
|
-
]);
|
|
908
1682
|
class NgxDynamicFormModule {
|
|
909
|
-
static forRoot() {
|
|
1683
|
+
static forRoot(controlProviders, groupProvider) {
|
|
910
1684
|
return {
|
|
911
1685
|
ngModule: NgxDynamicFormModule,
|
|
912
1686
|
providers: [
|
|
913
1687
|
DynamicFormService,
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
}
|
|
1688
|
+
OpenApiService,
|
|
1689
|
+
provideFormControl(DynamicFormFileComponent, DynamicFormFileComponent.acceptor, DynamicFormFileComponent.loader),
|
|
1690
|
+
provideFormControl(DynamicFormInputComponent, DynamicFormInputComponent.acceptor, DynamicFormInputComponent.loader),
|
|
1691
|
+
provideFormControl(DynamicFormSelectComponent, DynamicFormSelectComponent.acceptor, DynamicFormSelectComponent.loader),
|
|
1692
|
+
provideFormControl(DynamicFormStaticComponent, DynamicFormStaticComponent.acceptor, DynamicFormStaticComponent.loader),
|
|
1693
|
+
provideFormControl(DynamicFormModelComponent, DynamicFormModelComponent.acceptor, DynamicFormModelComponent.loader),
|
|
1694
|
+
...(controlProviders || []),
|
|
1695
|
+
groupProvider || provideFormGroup(DynamicFormGroupComponent)
|
|
923
1696
|
]
|
|
924
1697
|
};
|
|
925
1698
|
}
|
|
@@ -946,16 +1719,7 @@ NgxDynamicFormModule.decorators = [
|
|
|
946
1719
|
NgxUtilsModule
|
|
947
1720
|
],
|
|
948
1721
|
entryComponents: components,
|
|
949
|
-
providers:
|
|
950
|
-
...pipes,
|
|
951
|
-
{ provide: NG_VALIDATORS, useValue: ɵ0$1, multi: true },
|
|
952
|
-
{ provide: NG_VALIDATORS, useValue: ɵ1, multi: true },
|
|
953
|
-
{ provide: NG_VALIDATORS, useValue: ɵ2, multi: true },
|
|
954
|
-
{
|
|
955
|
-
provide: DYNAMIC_VALIDATORS,
|
|
956
|
-
useValue: ɵ3
|
|
957
|
-
}
|
|
958
|
-
]
|
|
1722
|
+
providers: pipes
|
|
959
1723
|
},] }
|
|
960
1724
|
];
|
|
961
1725
|
|
|
@@ -963,5 +1727,5 @@ NgxDynamicFormModule.decorators = [
|
|
|
963
1727
|
* Generated bundle index. Do not edit.
|
|
964
1728
|
*/
|
|
965
1729
|
|
|
966
|
-
export { AsyncSubmitDirective,
|
|
1730
|
+
export { AsyncSubmitDirective, DynamicFormBaseComponent, DynamicFormComponent, DynamicFormControl, DynamicFormControlDirective, DynamicFormFileComponent, DynamicFormGroup, DynamicFormGroupComponent, DynamicFormInputComponent, DynamicFormModelComponent, DynamicFormSelectComponent, DynamicFormService, DynamicFormStaticComponent, DynamicFormTemplateDirective, DynamicFormsComponent, FORM_CONTROL_PROVIDER, FormControlComponent, FormFieldSet, FormFile, FormInput, FormModel, FormSelect, FormSerializable, FormStatic, FormUtilities, NgxDynamicFormModule, OpenApiService, createFormControl, createFormInput, createFormModel, createFormSelect, createFormStatic, defaultSerializer, defineFormControl, getFormControl, getFormFieldSets, getFormSerializer, provideFormControl, provideFormGroup, FORM_GROUP_TYPE as ɵa, components as ɵb, directives as ɵc, pipes as ɵd, DynamicFormGroupDirective as ɵe };
|
|
967
1731
|
//# sourceMappingURL=stemy-ngx-dynamic-form.js.map
|