@stemy/ngx-dynamic-form 10.2.22 → 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 -902
- 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 -386
- 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 -594
- 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,448 +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;
|
|
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
|
-
? parseFloat((`${subControl.value}` || "0").replace(/,/gi, ".")) || null
|
|
307
|
-
: subControl.value;
|
|
308
|
-
continue;
|
|
309
|
-
}
|
|
310
|
-
result[subModel.id] = subControl.value;
|
|
311
|
-
}
|
|
312
|
-
return result;
|
|
313
|
-
});
|
|
665
|
+
static validateRequired(control) {
|
|
666
|
+
const value = control.value;
|
|
667
|
+
return Promise.resolve(!ObjectUtils.isNumber(value) && !value ? "error.required" : null);
|
|
314
668
|
}
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
if (subModel instanceof DynamicFormArrayModel$1) {
|
|
322
|
-
const length = Array.isArray(subControl.value) ? subControl.value.length : 0;
|
|
323
|
-
const subArray = subControl;
|
|
324
|
-
for (let i = 0; i < length; i++) {
|
|
325
|
-
const itemModel = subModel.get(i);
|
|
326
|
-
this.notifyChangesRecursive(itemModel.group, subArray.at(i));
|
|
327
|
-
}
|
|
328
|
-
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 } });
|
|
329
675
|
}
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
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 } });
|
|
333
686
|
}
|
|
334
|
-
|
|
335
|
-
}
|
|
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;
|
|
336
738
|
}
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
});
|
|
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
|
+
}));
|
|
355
757
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
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;
|
|
361
764
|
});
|
|
362
765
|
}
|
|
363
|
-
|
|
766
|
+
getFormInputsForSchemaDef(schema) {
|
|
767
|
+
const inputs = {};
|
|
364
768
|
if (!schema)
|
|
365
|
-
return
|
|
366
|
-
|
|
769
|
+
return inputs;
|
|
770
|
+
inputs.schema = schema;
|
|
771
|
+
inputs.serializers = {};
|
|
772
|
+
inputs.controls = Object.keys(schema.properties || {}).map(p => {
|
|
367
773
|
const property = schema.properties[p];
|
|
368
|
-
|
|
774
|
+
property.id = p;
|
|
775
|
+
inputs.serializers[p] = (id, parent) => {
|
|
776
|
+
return Promise.resolve(parent.model[id]);
|
|
777
|
+
};
|
|
778
|
+
return this.getFormControlForProperty(property, schema);
|
|
369
779
|
}).filter(t => null !== t);
|
|
780
|
+
return inputs;
|
|
370
781
|
}
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
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));
|
|
375
785
|
}
|
|
376
786
|
switch (property.type) {
|
|
377
787
|
case "string":
|
|
378
788
|
case "number":
|
|
379
|
-
case "integer":
|
|
380
|
-
return new DynamicInputModel(this.getFormInputConfig(property, schema));
|
|
381
|
-
case "textarea":
|
|
382
|
-
return new DynamicTextAreaModel(this.getFormTextareaConfig(property, schema));
|
|
383
789
|
case "boolean":
|
|
384
|
-
|
|
790
|
+
case "textarea":
|
|
791
|
+
return createFormInput(property.id, this.getFormInputData(property, schema));
|
|
385
792
|
case "list":
|
|
386
|
-
return
|
|
387
|
-
case "array":
|
|
388
|
-
if (((_a = property.items) === null || _a === void 0 ? void 0 : _a.$ref) || property.$ref) {
|
|
389
|
-
return new DynamicFormArrayModel(this.getFormArrayConfig(property, schema));
|
|
390
|
-
}
|
|
391
|
-
else if (((_b = property.items) === null || _b === void 0 ? void 0 : _b.enum) || property.enum) {
|
|
392
|
-
return new DynamicSelectModel(this.getFormSelectConfig(property, schema));
|
|
393
|
-
}
|
|
394
|
-
else {
|
|
395
|
-
return new DynamicInputModel(this.getFormInputConfig(property, schema));
|
|
396
|
-
}
|
|
793
|
+
return createFormSelect(property.id, this.getFormSelectData(property, schema));
|
|
397
794
|
case "file":
|
|
398
|
-
return
|
|
399
|
-
}
|
|
400
|
-
if (property.$ref) {
|
|
401
|
-
return new DynamicFormGroupModel(this.getFormGroupConfig(property, schema));
|
|
795
|
+
return createFormFile(property.id, this.getFormFileData(property, schema));
|
|
402
796
|
}
|
|
403
797
|
return null;
|
|
404
798
|
}
|
|
405
|
-
|
|
406
|
-
const validators = this.getValidators(property, schema);
|
|
407
|
-
const errorMessages = Object.keys(validators).reduce((res, key) => {
|
|
408
|
-
res[key] = `error.${key}`;
|
|
409
|
-
return res;
|
|
410
|
-
}, {});
|
|
799
|
+
getBaseFormData(property, schema) {
|
|
411
800
|
return {
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
disabled: property.disabled,
|
|
416
|
-
validators,
|
|
417
|
-
errorMessages,
|
|
418
|
-
additional: Object.assign({}, property)
|
|
801
|
+
readonly: property.readonly ? FormUtilities.readonly : null,
|
|
802
|
+
shouldSerialize: FormUtilities.checkReadonly,
|
|
803
|
+
validators: this.getValidators(property, schema)
|
|
419
804
|
};
|
|
420
805
|
}
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
const subSchema = this.schemas[ref.split("/").pop()];
|
|
425
|
-
return Object.assign(this.getFormControlConfig(property, schema), { groupFactory: () => this.getFormModelForSchemaDef(subSchema) });
|
|
426
|
-
}
|
|
427
|
-
getFormGroupConfig(property, schema) {
|
|
428
|
-
const ref = property.$ref || "";
|
|
429
|
-
const subSchema = this.schemas[ref.split("/").pop()];
|
|
430
|
-
return Object.assign(this.getFormControlConfig(property, schema), { group: this.getFormModelForSchemaDef(subSchema) });
|
|
431
|
-
}
|
|
432
|
-
getFormInputConfig(property, schema) {
|
|
433
|
-
var _a;
|
|
434
|
-
let inputType = StringUtils.has(property.id, "password", "Password") ? "password" : (((_a = property.items) === null || _a === void 0 ? void 0 : _a.type) || property.type);
|
|
435
|
-
switch (inputType) {
|
|
806
|
+
getFormInputData(property, schema) {
|
|
807
|
+
let type = StringUtils.has(property.id, "password", "Password") ? "password" : property.type;
|
|
808
|
+
switch (property.type) {
|
|
436
809
|
case "boolean":
|
|
437
|
-
|
|
810
|
+
type = "checkbox";
|
|
438
811
|
break;
|
|
439
812
|
case "textarea":
|
|
440
|
-
|
|
441
|
-
break;
|
|
442
|
-
case "integer":
|
|
443
|
-
inputType = "number";
|
|
813
|
+
type = "textarea";
|
|
444
814
|
break;
|
|
445
815
|
}
|
|
446
|
-
return Object.assign(this.
|
|
447
|
-
inputType,
|
|
448
|
-
autoComplete: property.autoComplete || "off",
|
|
449
|
-
multiple: property.type == "array",
|
|
450
|
-
accept: ObjectUtils.isString(property.accept) ? property.accept : null,
|
|
451
|
-
mask: ObjectUtils.isString(property.mask) ? property.mask : null,
|
|
452
|
-
pattern: ObjectUtils.isString(property.pattern) ? property.pattern : null,
|
|
453
|
-
step: isNaN(property.step) ? 1 : property.step,
|
|
454
|
-
min: isNaN(property.min) ? Number.MIN_SAFE_INTEGER : property.min,
|
|
455
|
-
max: isNaN(property.max) ? Number.MAX_SAFE_INTEGER : property.max,
|
|
456
|
-
});
|
|
457
|
-
}
|
|
458
|
-
getFormTextareaConfig(property, schema) {
|
|
459
|
-
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
460
|
-
cols: property.cols || null,
|
|
461
|
-
rows: property.rows || 10,
|
|
462
|
-
wrap: property.wrap || false,
|
|
463
|
-
autoComplete: property.autoComplete || "off",
|
|
464
|
-
multiple: property.type == "array"
|
|
465
|
-
});
|
|
816
|
+
return Object.assign(Object.assign({}, this.getBaseFormData(property, schema)), { type });
|
|
466
817
|
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
});
|
|
472
|
-
}
|
|
473
|
-
getFormCheckboxConfig(property, schema) {
|
|
474
|
-
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
475
|
-
indeterminate: property.indeterminate === true
|
|
476
|
-
});
|
|
477
|
-
}
|
|
478
|
-
translateOptions(options) {
|
|
479
|
-
return __awaiter(this, void 0, void 0, function* () {
|
|
480
|
-
if (!options)
|
|
481
|
-
return [];
|
|
482
|
-
for (const option of options) {
|
|
483
|
-
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}` })));
|
|
484
822
|
}
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
const $enum = ((_a = property.items) === null || _a === void 0 ? void 0 : _a.enum) || property.enum;
|
|
491
|
-
if (property.optionsPath) {
|
|
492
|
-
return new FormSubject((formModel, control) => {
|
|
493
|
-
let path = property.optionsPath;
|
|
494
|
-
let target = control;
|
|
495
|
-
if (path.startsWith("$root")) {
|
|
496
|
-
path = path.substr(5);
|
|
497
|
-
while (target.parent) {
|
|
498
|
-
target = target.parent;
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
while (path.startsWith(".")) {
|
|
502
|
-
path = path.substr(1);
|
|
503
|
-
if (target.parent) {
|
|
504
|
-
target = target.parent;
|
|
505
|
-
}
|
|
506
|
-
}
|
|
507
|
-
const value = ObjectUtils.getValue(target.value, path);
|
|
508
|
-
const options = (!ObjectUtils.isArray(value) ? [] : value).map(value => ({ value, label: value }));
|
|
509
|
-
return this.translateOptions(options);
|
|
510
|
-
});
|
|
511
|
-
}
|
|
512
|
-
if (ObjectUtils.isArray($enum)) {
|
|
513
|
-
return new FormSubject(() => {
|
|
514
|
-
const options = $enum.map(value => {
|
|
515
|
-
const label = property.translatable ? `${property.id}.${value}` : value;
|
|
516
|
-
return { value, label };
|
|
517
|
-
});
|
|
518
|
-
return this.translateOptions(options);
|
|
519
|
-
});
|
|
520
|
-
}
|
|
521
|
-
return new FormSubject(() => __awaiter(this, void 0, void 0, function* () {
|
|
522
|
-
this.api.cache[property.endpoint] = this.api.cache[property.endpoint] || this.api.list(property.endpoint, this.api.makeListParams(1, -1)).then(result => {
|
|
523
|
-
return result.items.map(i => {
|
|
524
|
-
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
|
+
});
|
|
525
828
|
});
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}));
|
|
829
|
+
return this.api.cache[property.endpoint];
|
|
830
|
+
};
|
|
831
|
+
return Object.assign(Object.assign({}, this.getBaseFormData(property, schema)), { options });
|
|
530
832
|
}
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
const { accept, autoUpload, maxSize, minSize, removeUrl, showFileList } = property;
|
|
534
|
-
return Object.assign(this.getFormControlConfig(property, schema), {
|
|
535
|
-
url,
|
|
536
|
-
accept,
|
|
537
|
-
autoUpload,
|
|
538
|
-
maxSize,
|
|
539
|
-
minSize,
|
|
540
|
-
removeUrl,
|
|
541
|
-
showFileList
|
|
542
|
-
});
|
|
833
|
+
getFormFileData(property, schema) {
|
|
834
|
+
return Object.assign(Object.assign({}, this.getBaseFormData(property, schema)), { multi: property.multi });
|
|
543
835
|
}
|
|
544
836
|
getValidators(property, schema) {
|
|
545
|
-
const validators =
|
|
546
|
-
if (
|
|
547
|
-
validators.
|
|
837
|
+
const validators = [];
|
|
838
|
+
if (schema.required.indexOf(property.id) >= 0) {
|
|
839
|
+
validators.push(FormUtilities.validateRequired);
|
|
548
840
|
}
|
|
549
841
|
if (property.minLength) {
|
|
550
|
-
validators.
|
|
842
|
+
validators.push({
|
|
843
|
+
type: FormUtilities,
|
|
844
|
+
func: FormUtilities.validateMinLength,
|
|
845
|
+
params: [property.minLength]
|
|
846
|
+
});
|
|
551
847
|
}
|
|
552
848
|
if (property.maxLength) {
|
|
553
|
-
validators.
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
if (property.max) {
|
|
559
|
-
validators.max = property.max;
|
|
849
|
+
validators.push({
|
|
850
|
+
type: FormUtilities,
|
|
851
|
+
func: FormUtilities.validateMaxLength,
|
|
852
|
+
params: [property.maxLength]
|
|
853
|
+
});
|
|
560
854
|
}
|
|
561
855
|
switch (property.format) {
|
|
562
856
|
case "email":
|
|
563
|
-
validators.
|
|
857
|
+
validators.push(FormUtilities.validateEmail);
|
|
564
858
|
break;
|
|
565
859
|
}
|
|
566
860
|
return validators;
|
|
567
861
|
}
|
|
568
862
|
}
|
|
569
|
-
|
|
863
|
+
OpenApiService.decorators = [
|
|
570
864
|
{ type: Injectable }
|
|
571
865
|
];
|
|
572
|
-
|
|
573
|
-
{ type:
|
|
574
|
-
{ type: DynamicFormValidationService$1 },
|
|
575
|
-
{ type: OpenApiService }
|
|
866
|
+
OpenApiService.ctorParameters = () => [
|
|
867
|
+
{ type: ApiService }
|
|
576
868
|
];
|
|
577
869
|
|
|
578
870
|
class AsyncSubmitDirective {
|
|
579
871
|
constructor(toaster, cdr, elem, renderer) {
|
|
580
872
|
this.toaster = toaster;
|
|
581
873
|
this.cdr = cdr;
|
|
582
|
-
this.elem = elem;
|
|
583
|
-
this.renderer = renderer;
|
|
584
874
|
this.onSuccess = new EventEmitter();
|
|
585
875
|
this.onError = new EventEmitter();
|
|
586
876
|
if (elem.nativeElement.tagName !== "BUTTON")
|
|
@@ -590,26 +880,18 @@ class AsyncSubmitDirective {
|
|
|
590
880
|
get isDisabled() {
|
|
591
881
|
return this.disabled;
|
|
592
882
|
}
|
|
593
|
-
set isDisabled(value) {
|
|
594
|
-
this.disabled = value;
|
|
595
|
-
if (value) {
|
|
596
|
-
this.renderer.setAttribute(this.elem.nativeElement, "disabled", "disabled");
|
|
597
|
-
return;
|
|
598
|
-
}
|
|
599
|
-
this.renderer.removeAttribute(this.elem.nativeElement, "disabled");
|
|
600
|
-
}
|
|
601
883
|
get isLoading() {
|
|
602
884
|
return this.loading;
|
|
603
885
|
}
|
|
604
886
|
ngOnInit() {
|
|
605
887
|
if (!this.form)
|
|
606
888
|
return;
|
|
607
|
-
this.
|
|
889
|
+
this.disabled = this.form.status !== "VALID";
|
|
608
890
|
this.cdr.detectChanges();
|
|
609
|
-
this.onStatusChange = this.form.onStatusChange.subscribe(
|
|
610
|
-
this.
|
|
891
|
+
this.onStatusChange = this.form.onStatusChange.subscribe(form => {
|
|
892
|
+
this.disabled = form.status !== "VALID";
|
|
611
893
|
this.cdr.detectChanges();
|
|
612
|
-
if (!this.callback ||
|
|
894
|
+
if (!this.callback || form.status == "PENDING")
|
|
613
895
|
return;
|
|
614
896
|
if (!this.disabled) {
|
|
615
897
|
this.callback();
|
|
@@ -635,7 +917,7 @@ class AsyncSubmitDirective {
|
|
|
635
917
|
if (this.loading)
|
|
636
918
|
return;
|
|
637
919
|
this.loading = true;
|
|
638
|
-
this.method(this.form
|
|
920
|
+
this.method(this.form).then(result => {
|
|
639
921
|
this.loading = false;
|
|
640
922
|
if (result) {
|
|
641
923
|
this.onSuccess.emit(result);
|
|
@@ -665,7 +947,6 @@ AsyncSubmitDirective.ctorParameters = () => [
|
|
|
665
947
|
AsyncSubmitDirective.propDecorators = {
|
|
666
948
|
method: [{ type: Input, args: ["async-submit",] }],
|
|
667
949
|
form: [{ type: Input }],
|
|
668
|
-
context: [{ type: Input }],
|
|
669
950
|
onSuccess: [{ type: Output }],
|
|
670
951
|
onError: [{ type: Output }],
|
|
671
952
|
isDisabled: [{ type: HostBinding, args: ["class.disabled",] }],
|
|
@@ -673,78 +954,194 @@ AsyncSubmitDirective.propDecorators = {
|
|
|
673
954
|
click: [{ type: HostListener, args: ["click",] }]
|
|
674
955
|
};
|
|
675
956
|
|
|
676
|
-
class
|
|
677
|
-
constructor(
|
|
678
|
-
|
|
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) {
|
|
679
1026
|
this.formService = formService;
|
|
680
|
-
this.
|
|
681
|
-
this.
|
|
682
|
-
this.
|
|
683
|
-
this.
|
|
1027
|
+
this.name = "";
|
|
1028
|
+
this.controlTemplates = {};
|
|
1029
|
+
this.labelTemplates = {};
|
|
1030
|
+
this.inputTemplates = {};
|
|
1031
|
+
this.prefixTemplates = {};
|
|
1032
|
+
this.suffixTemplates = {};
|
|
1033
|
+
this.onChange = new EventEmitter();
|
|
684
1034
|
this.onStatusChange = new EventEmitter();
|
|
685
|
-
this.
|
|
1035
|
+
this.onInit = new EventEmitter();
|
|
686
1036
|
this.onSubmit = new EventEmitter();
|
|
687
|
-
this.
|
|
688
|
-
this.
|
|
689
|
-
this.groupSubscription = new Subscription();
|
|
690
|
-
this.labelPrefix = "label";
|
|
691
|
-
}
|
|
692
|
-
get status() {
|
|
693
|
-
return !this.group ? null : this.group.status;
|
|
1037
|
+
this.injector = formService.injector;
|
|
1038
|
+
this.cdr = cdr;
|
|
694
1039
|
}
|
|
695
|
-
|
|
696
|
-
this
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
this.onStatusChange.emit(this);
|
|
700
|
-
}), this.group.valueChanges.subscribe(() => {
|
|
701
|
-
this.onValueChange.emit(this);
|
|
702
|
-
this.formService.notifyChanges(this.model, this.group);
|
|
703
|
-
}));
|
|
1040
|
+
get root() {
|
|
1041
|
+
let form = this;
|
|
1042
|
+
while (ObjectUtils.isDefined(form.parent)) {
|
|
1043
|
+
form = form.parent;
|
|
704
1044
|
}
|
|
1045
|
+
return form;
|
|
705
1046
|
}
|
|
706
|
-
|
|
707
|
-
this.
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
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
|
+
}, {});
|
|
718
1070
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
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
|
+
};
|
|
723
1116
|
}
|
|
724
|
-
|
|
725
|
-
this.
|
|
726
|
-
this.changeDetectorRef.detectChanges();
|
|
1117
|
+
get status() {
|
|
1118
|
+
return this.group.state;
|
|
727
1119
|
}
|
|
728
|
-
|
|
729
|
-
this.
|
|
730
|
-
this.changeDetectorRef.detectChanges();
|
|
1120
|
+
get formControls() {
|
|
1121
|
+
return this.group.formControls;
|
|
731
1122
|
}
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
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
|
+
}
|
|
735
1133
|
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
this.
|
|
1134
|
+
// --- Custom ---
|
|
1135
|
+
onFormSubmit() {
|
|
1136
|
+
const root = this.root;
|
|
1137
|
+
root.validate().then(() => root.onSubmit.emit(this), () => { });
|
|
739
1138
|
}
|
|
1139
|
+
// --- IDynamicForm ---
|
|
740
1140
|
validate(showErrors = true) {
|
|
741
|
-
if (!this.group)
|
|
742
|
-
return Promise.resolve();
|
|
743
1141
|
return new Promise((resolve, reject) => {
|
|
744
1142
|
this.group.statusChanges.pipe(first(status => status == "VALID" || status == "INVALID")).subscribe(status => {
|
|
745
|
-
if (showErrors)
|
|
746
|
-
this.
|
|
747
|
-
}
|
|
1143
|
+
if (showErrors)
|
|
1144
|
+
this.group.showErrors();
|
|
748
1145
|
if (status == "VALID") {
|
|
749
1146
|
resolve(null);
|
|
750
1147
|
return;
|
|
@@ -755,172 +1152,547 @@ class DynamicBaseFormComponent extends DynamicFormComponent {
|
|
|
755
1152
|
});
|
|
756
1153
|
}
|
|
757
1154
|
serialize(validate) {
|
|
758
|
-
return
|
|
759
|
-
|
|
760
|
-
|
|
1155
|
+
return new Promise((resolve, reject) => {
|
|
1156
|
+
const serialize = () => {
|
|
1157
|
+
this.group.serialize().then(resolve);
|
|
1158
|
+
};
|
|
761
1159
|
if (validate) {
|
|
762
|
-
|
|
1160
|
+
this.validate().then(serialize, reject);
|
|
1161
|
+
return;
|
|
763
1162
|
}
|
|
764
|
-
|
|
1163
|
+
serialize();
|
|
765
1164
|
});
|
|
766
1165
|
}
|
|
1166
|
+
check() {
|
|
1167
|
+
return this.group.check();
|
|
1168
|
+
}
|
|
1169
|
+
getControl(id) {
|
|
1170
|
+
return this.group.getControl(id);
|
|
1171
|
+
}
|
|
767
1172
|
}
|
|
768
|
-
|
|
1173
|
+
DynamicFormComponent.decorators = [
|
|
769
1174
|
{ type: Component, args: [{
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
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 }]
|
|
773
1179
|
},] }
|
|
774
1180
|
];
|
|
775
|
-
|
|
776
|
-
{ type: DynamicFormService, decorators: [{ type: Inject, args: [DynamicFormService,] }] },
|
|
777
|
-
{ type: EventsService, decorators: [{ type: Inject, args: [EventsService,] }] },
|
|
1181
|
+
DynamicFormComponent.ctorParameters = () => [
|
|
778
1182
|
{ type: ChangeDetectorRef },
|
|
779
|
-
{ type:
|
|
1183
|
+
{ type: DynamicFormService }
|
|
780
1184
|
];
|
|
781
|
-
|
|
1185
|
+
DynamicFormComponent.propDecorators = {
|
|
782
1186
|
group: [{ type: Input }],
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
change: [{ type: Output }],
|
|
788
|
-
focus: [{ type: Output }],
|
|
789
|
-
contentTemplates: [{ type: ContentChildren, args: [DynamicTemplateDirective,] }],
|
|
790
|
-
viewTemplates: [{ type: ViewChildren, args: [DynamicTemplateDirective,] }],
|
|
791
|
-
onStatusChange: [{ type: Output }],
|
|
792
|
-
onValueChange: [{ type: Output }],
|
|
793
|
-
onSubmit: [{ type: Output }],
|
|
794
|
-
ngForm: [{ type: ViewChild, args: [NgForm,] }]
|
|
1187
|
+
controls: [{ type: Input }],
|
|
1188
|
+
serializers: [{ type: Input }],
|
|
1189
|
+
fieldSets: [{ type: Input }],
|
|
1190
|
+
data: [{ type: Input }]
|
|
795
1191
|
};
|
|
796
1192
|
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
this.
|
|
802
|
-
this.
|
|
803
|
-
this.
|
|
804
|
-
this.
|
|
805
|
-
this.componentService = componentService;
|
|
806
|
-
this.relationService = relationService;
|
|
807
|
-
this.context = null;
|
|
808
|
-
this.blur = new EventEmitter();
|
|
809
|
-
this.change = new EventEmitter();
|
|
810
|
-
this.focus = new EventEmitter();
|
|
811
|
-
}
|
|
812
|
-
get componentType() {
|
|
813
|
-
var _a;
|
|
814
|
-
return (_a = this.componentService.getCustomComponentType(this.model)) !== null && _a !== void 0 ? _a : this.getComponentType(this.model);
|
|
815
|
-
}
|
|
816
|
-
get startTemplate() {
|
|
817
|
-
return (this.model.type == DYNAMIC_FORM_CONTROL_TYPE_ARRAY)
|
|
818
|
-
? this.layoutService.getAlignedTemplate(this.model, this.templates, "ARRAY_START")
|
|
819
|
-
: this.layoutService.getStartTemplate(this.model, this.templates);
|
|
820
|
-
}
|
|
821
|
-
get endTemplate() {
|
|
822
|
-
return (this.model.type == DYNAMIC_FORM_CONTROL_TYPE_ARRAY)
|
|
823
|
-
? this.layoutService.getAlignedTemplate(this.model, this.templates, "ARRAY_END")
|
|
824
|
-
: this.layoutService.getEndTemplate(this.model, this.templates);
|
|
825
|
-
}
|
|
826
|
-
get formService() {
|
|
827
|
-
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 = {};
|
|
828
1201
|
}
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
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));
|
|
832
1391
|
return;
|
|
833
|
-
|
|
834
|
-
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)));
|
|
835
1402
|
});
|
|
836
1403
|
}
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
var _a;
|
|
843
|
-
super.createFormControlComponent();
|
|
844
|
-
const component = (_a = this.componentRef) === null || _a === void 0 ? void 0 : _a.instance;
|
|
845
|
-
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);
|
|
846
1409
|
return;
|
|
847
|
-
|
|
1410
|
+
}
|
|
1411
|
+
this.control.setValue(null);
|
|
848
1412
|
}
|
|
849
|
-
|
|
850
|
-
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}`);
|
|
851
1435
|
}
|
|
852
1436
|
}
|
|
853
|
-
|
|
1437
|
+
DynamicFormFileComponent.decorators = [
|
|
854
1438
|
{ type: Component, args: [{
|
|
855
|
-
selector: "dynamic-
|
|
856
|
-
template: "",
|
|
857
|
-
|
|
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"]
|
|
858
1442
|
},] }
|
|
859
1443
|
];
|
|
860
|
-
|
|
861
|
-
{ type:
|
|
862
|
-
{ type:
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
{
|
|
867
|
-
|
|
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
|
+
},] }
|
|
868
1507
|
];
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
hostClass: [{ type: Input }],
|
|
875
|
-
inputTemplateList: [{ type: Input, args: ["templates",] }],
|
|
876
|
-
layout: [{ type: Input }],
|
|
877
|
-
model: [{ type: Input }],
|
|
878
|
-
blur: [{ type: Output }],
|
|
879
|
-
change: [{ type: Output }],
|
|
880
|
-
focus: [{ type: Output }],
|
|
881
|
-
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",] }]
|
|
882
1513
|
};
|
|
883
1514
|
|
|
884
|
-
class
|
|
885
|
-
|
|
886
|
-
|
|
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();
|
|
887
1593
|
}
|
|
888
1594
|
}
|
|
889
|
-
|
|
890
|
-
{ 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
|
+
},] }
|
|
891
1601
|
];
|
|
892
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
|
+
|
|
893
1662
|
// --- Components ---
|
|
894
1663
|
const components = [
|
|
895
|
-
|
|
896
|
-
|
|
1664
|
+
DynamicFormsComponent,
|
|
1665
|
+
DynamicFormComponent,
|
|
1666
|
+
DynamicFormGroupComponent,
|
|
1667
|
+
DynamicFormFileComponent,
|
|
1668
|
+
DynamicFormInputComponent,
|
|
1669
|
+
DynamicFormSelectComponent,
|
|
1670
|
+
DynamicFormStaticComponent,
|
|
1671
|
+
DynamicFormModelComponent
|
|
897
1672
|
];
|
|
898
1673
|
// --- Directives ---
|
|
899
1674
|
const directives = [
|
|
900
1675
|
AsyncSubmitDirective,
|
|
1676
|
+
DynamicFormControlDirective,
|
|
1677
|
+
DynamicFormGroupDirective,
|
|
1678
|
+
DynamicFormTemplateDirective
|
|
901
1679
|
];
|
|
902
1680
|
// --- Pipes ---
|
|
903
1681
|
const pipes = [];
|
|
904
|
-
const ɵ0$1 = validateJSON, ɵ1 = validateRequiredTranslation, ɵ2 = validatePhone, ɵ3 = new Map([
|
|
905
|
-
["validateJSON", validateJSON],
|
|
906
|
-
["validateRequiredTranslation", validateRequiredTranslation],
|
|
907
|
-
["validatePhone", validatePhone],
|
|
908
|
-
]);
|
|
909
1682
|
class NgxDynamicFormModule {
|
|
910
|
-
static forRoot() {
|
|
1683
|
+
static forRoot(controlProviders, groupProvider) {
|
|
911
1684
|
return {
|
|
912
1685
|
ngModule: NgxDynamicFormModule,
|
|
913
1686
|
providers: [
|
|
914
1687
|
DynamicFormService,
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
}
|
|
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)
|
|
924
1696
|
]
|
|
925
1697
|
};
|
|
926
1698
|
}
|
|
@@ -947,16 +1719,7 @@ NgxDynamicFormModule.decorators = [
|
|
|
947
1719
|
NgxUtilsModule
|
|
948
1720
|
],
|
|
949
1721
|
entryComponents: components,
|
|
950
|
-
providers:
|
|
951
|
-
...pipes,
|
|
952
|
-
{ provide: NG_VALIDATORS, useValue: ɵ0$1, multi: true },
|
|
953
|
-
{ provide: NG_VALIDATORS, useValue: ɵ1, multi: true },
|
|
954
|
-
{ provide: NG_VALIDATORS, useValue: ɵ2, multi: true },
|
|
955
|
-
{
|
|
956
|
-
provide: DYNAMIC_VALIDATORS,
|
|
957
|
-
useValue: ɵ3
|
|
958
|
-
}
|
|
959
|
-
]
|
|
1722
|
+
providers: pipes
|
|
960
1723
|
},] }
|
|
961
1724
|
];
|
|
962
1725
|
|
|
@@ -964,5 +1727,5 @@ NgxDynamicFormModule.decorators = [
|
|
|
964
1727
|
* Generated bundle index. Do not edit.
|
|
965
1728
|
*/
|
|
966
1729
|
|
|
967
|
-
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 };
|
|
968
1731
|
//# sourceMappingURL=stemy-ngx-dynamic-form.js.map
|