@olafvv/ngx-dynamic-form 0.0.2
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/README.md +55 -0
- package/esm2022/lib/components/dynamic-form/dynamic-form.component.mjs +59 -0
- package/esm2022/lib/components/dynamic-form-field/dynamic-form-field.component.mjs +129 -0
- package/esm2022/lib/controls/button/dynamic-button.component.mjs +22 -0
- package/esm2022/lib/controls/button/dynamic-button.model.mjs +12 -0
- package/esm2022/lib/controls/checkbox/dynamic-checkbox.component.mjs +32 -0
- package/esm2022/lib/controls/checkbox/dynamic-checkbox.model.mjs +21 -0
- package/esm2022/lib/controls/index.mjs +7 -0
- package/esm2022/lib/controls/input/dynamic-input.component.mjs +51 -0
- package/esm2022/lib/controls/input/dynamic-input.model.mjs +18 -0
- package/esm2022/lib/controls/readonly/dynamic-readonly.component.mjs +18 -0
- package/esm2022/lib/controls/readonly/dynamic-readonly.model.mjs +9 -0
- package/esm2022/lib/controls/select/dynamic-select.component.mjs +42 -0
- package/esm2022/lib/controls/select/dynamic-select.model.mjs +11 -0
- package/esm2022/lib/controls/textarea/dynamic-textarea.component.mjs +45 -0
- package/esm2022/lib/controls/textarea/dynamic-textarea.model.mjs +15 -0
- package/esm2022/lib/models/classes/dynamic-form-field-base-component.mjs +34 -0
- package/esm2022/lib/models/classes/dynamic-form-field-model.mjs +24 -0
- package/esm2022/lib/models/classes/dynamic-form-field-option-model.mjs +48 -0
- package/esm2022/lib/models/classes/dynamic-form-field-value-model.mjs +24 -0
- package/esm2022/lib/models/classes/dynamic-form-validators.mjs +73 -0
- package/esm2022/lib/models/constants/dynamic-relations.const.mjs +47 -0
- package/esm2022/lib/models/index.mjs +11 -0
- package/esm2022/lib/models/interfaces/dynamic-form-field-config.interface.mjs +2 -0
- package/esm2022/lib/models/interfaces/dynamic-form-validator.interface.mjs +2 -0
- package/esm2022/lib/models/tokens/dynamic-form-field-map-fn.token.mjs +3 -0
- package/esm2022/lib/models/types/dynamic-form-config.type.mjs +2 -0
- package/esm2022/lib/models/types/dynamic-form-hook.type.mjs +2 -0
- package/esm2022/lib/models/types/related-form-controls.type.mjs +2 -0
- package/esm2022/lib/services/dynamic-form-relations.service.mjs +103 -0
- package/esm2022/lib/services/dynamic-form.service.mjs +77 -0
- package/esm2022/lib/services/dynamic-validations.service.mjs +37 -0
- package/esm2022/olafvv-ngx-dynamic-form.mjs +5 -0
- package/esm2022/public-api.mjs +8 -0
- package/fesm2022/olafvv-ngx-dynamic-form.mjs +873 -0
- package/fesm2022/olafvv-ngx-dynamic-form.mjs.map +1 -0
- package/index.d.ts +5 -0
- package/lib/components/dynamic-form/dynamic-form.component.d.ts +32 -0
- package/lib/components/dynamic-form-field/dynamic-form-field.component.d.ts +44 -0
- package/lib/controls/button/dynamic-button.component.d.ts +11 -0
- package/lib/controls/button/dynamic-button.model.d.ts +15 -0
- package/lib/controls/checkbox/dynamic-checkbox.component.d.ts +15 -0
- package/lib/controls/checkbox/dynamic-checkbox.model.d.ts +15 -0
- package/lib/controls/index.d.ts +6 -0
- package/lib/controls/input/dynamic-input.component.d.ts +19 -0
- package/lib/controls/input/dynamic-input.model.d.ts +27 -0
- package/lib/controls/readonly/dynamic-readonly.component.d.ts +10 -0
- package/lib/controls/readonly/dynamic-readonly.model.d.ts +9 -0
- package/lib/controls/select/dynamic-select.component.d.ts +16 -0
- package/lib/controls/select/dynamic-select.model.d.ts +12 -0
- package/lib/controls/textarea/dynamic-textarea.component.d.ts +18 -0
- package/lib/controls/textarea/dynamic-textarea.model.d.ts +21 -0
- package/lib/models/classes/dynamic-form-field-base-component.d.ts +26 -0
- package/lib/models/classes/dynamic-form-field-model.d.ts +22 -0
- package/lib/models/classes/dynamic-form-field-option-model.d.ts +41 -0
- package/lib/models/classes/dynamic-form-field-value-model.d.ts +18 -0
- package/lib/models/classes/dynamic-form-validators.d.ts +48 -0
- package/lib/models/constants/dynamic-relations.const.d.ts +30 -0
- package/lib/models/index.d.ts +10 -0
- package/lib/models/interfaces/dynamic-form-field-config.interface.d.ts +60 -0
- package/lib/models/interfaces/dynamic-form-validator.interface.d.ts +6 -0
- package/lib/models/tokens/dynamic-form-field-map-fn.token.d.ts +2 -0
- package/lib/models/types/dynamic-form-config.type.d.ts +2 -0
- package/lib/models/types/dynamic-form-hook.type.d.ts +1 -0
- package/lib/models/types/related-form-controls.type.d.ts +4 -0
- package/lib/services/dynamic-form-relations.service.d.ts +26 -0
- package/lib/services/dynamic-form.service.d.ts +42 -0
- package/lib/services/dynamic-validations.service.d.ts +20 -0
- package/package.json +28 -0
- package/public-api.d.ts +4 -0
|
@@ -0,0 +1,873 @@
|
|
|
1
|
+
import { NgIf, NgFor, AsyncPipe, NgClass } from '@angular/common';
|
|
2
|
+
import * as i0 from '@angular/core';
|
|
3
|
+
import { InjectionToken, Injectable, Inject, Optional, Component, Input, EventEmitter, Output, ViewChild, inject, Injector, ViewContainerRef, ChangeDetectionStrategy } from '@angular/core';
|
|
4
|
+
import * as i1 from '@angular/forms';
|
|
5
|
+
import { UntypedFormControl, ReactiveFormsModule, Validators } from '@angular/forms';
|
|
6
|
+
import { map, BehaviorSubject, of, isObservable, startWith, distinctUntilChanged, Subscription } from 'rxjs';
|
|
7
|
+
import * as i1$1 from '@angular/material/button';
|
|
8
|
+
import { MatButtonModule } from '@angular/material/button';
|
|
9
|
+
import * as i2 from '@angular/material/checkbox';
|
|
10
|
+
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
11
|
+
import * as i1$2 from '@angular/material/form-field';
|
|
12
|
+
import { MatFormFieldModule } from '@angular/material/form-field';
|
|
13
|
+
import * as i5 from '@angular/material/icon';
|
|
14
|
+
import { MatIconModule } from '@angular/material/icon';
|
|
15
|
+
import * as i3 from '@angular/material/input';
|
|
16
|
+
import { MatInput, MatInputModule } from '@angular/material/input';
|
|
17
|
+
import * as i4 from '@angular/material/core';
|
|
18
|
+
import { MatOptionModule } from '@angular/material/core';
|
|
19
|
+
import * as i3$1 from '@angular/material/select';
|
|
20
|
+
import { MatSelectModule } from '@angular/material/select';
|
|
21
|
+
import * as i3$2 from '@angular/cdk/text-field';
|
|
22
|
+
|
|
23
|
+
const DYNAMIC_FORM_FIELD_MAP_FN = new InjectionToken('DYNAMIC_FORM_FIELD_MAP_FN');
|
|
24
|
+
|
|
25
|
+
class DynamicFormValidationsService {
|
|
26
|
+
/**
|
|
27
|
+
* Get all Validator Functions from the validator configuration
|
|
28
|
+
* @param validatorConfig
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
getValidatorFns(validatorConfig) {
|
|
32
|
+
return validatorConfig.map((v) => v.validator);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Update the validators on a FormControl based on the provided validator configuration.
|
|
36
|
+
* This will replace any existing validators on the control or removes all validators when none provided
|
|
37
|
+
* @param validatorConfig
|
|
38
|
+
* @param control
|
|
39
|
+
*/
|
|
40
|
+
updateValidators(validatorConfig, control) {
|
|
41
|
+
if (!validatorConfig || validatorConfig.length === 0) {
|
|
42
|
+
control.clearValidators();
|
|
43
|
+
}
|
|
44
|
+
else {
|
|
45
|
+
const validatorFns = this.getValidatorFns(validatorConfig);
|
|
46
|
+
control.setValidators(validatorFns);
|
|
47
|
+
}
|
|
48
|
+
control.updateValueAndValidity();
|
|
49
|
+
}
|
|
50
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormValidationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
51
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormValidationsService, providedIn: 'root' }); }
|
|
52
|
+
}
|
|
53
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormValidationsService, decorators: [{
|
|
54
|
+
type: Injectable,
|
|
55
|
+
args: [{
|
|
56
|
+
providedIn: 'root'
|
|
57
|
+
}]
|
|
58
|
+
}] });
|
|
59
|
+
|
|
60
|
+
class DynamicFormService {
|
|
61
|
+
constructor(DYNAMIC_FORM_FIELD_MAP_FN, fb, validatorsService) {
|
|
62
|
+
this.DYNAMIC_FORM_FIELD_MAP_FN = DYNAMIC_FORM_FIELD_MAP_FN;
|
|
63
|
+
this.fb = fb;
|
|
64
|
+
this.validatorsService = validatorsService;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Check if there is a function provided to use custom form controls
|
|
68
|
+
* @param model
|
|
69
|
+
* @returns
|
|
70
|
+
*/
|
|
71
|
+
getCustomControlComponentType(model) {
|
|
72
|
+
return typeof this.DYNAMIC_FORM_FIELD_MAP_FN === 'function' ? this.DYNAMIC_FORM_FIELD_MAP_FN(model) : null;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Create a FormGroup from the provided form configuration.
|
|
76
|
+
* Returns a FormGroup.
|
|
77
|
+
* @param config
|
|
78
|
+
* @returns
|
|
79
|
+
*/
|
|
80
|
+
createFormGroup(config) {
|
|
81
|
+
const group = this.fb.group({});
|
|
82
|
+
config.forEach((row) => {
|
|
83
|
+
row.forEach((controlConfig) => {
|
|
84
|
+
const controlValueConfig = controlConfig;
|
|
85
|
+
const controlOptions = {
|
|
86
|
+
updateOn: controlConfig.updateOn,
|
|
87
|
+
validators: this.validatorsService.getValidatorFns(controlConfig.validators)
|
|
88
|
+
};
|
|
89
|
+
const control = new UntypedFormControl({ value: controlValueConfig.value ?? controlValueConfig.defaultValue, disabled: controlValueConfig.disabled }, controlOptions);
|
|
90
|
+
group.addControl(controlConfig.name, control);
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
return group;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Transform any list (Observable) to a list of DynamicFormFieldOption which is used in any Dynamic Form Field with options (e.g. DynamicSelect).
|
|
97
|
+
* Generic types:
|
|
98
|
+
* T = The type of the items in the provided list
|
|
99
|
+
* K = The type of the value inside an DynamicFormFieldOption
|
|
100
|
+
* @param listObs
|
|
101
|
+
* @param labelCb
|
|
102
|
+
* @param valueCb
|
|
103
|
+
* @returns
|
|
104
|
+
*/
|
|
105
|
+
toDynamicOptionListObs(listObs, labelCb, valueCb) {
|
|
106
|
+
return listObs.pipe(map((list) => {
|
|
107
|
+
return list.map((item) => {
|
|
108
|
+
return {
|
|
109
|
+
label: labelCb(item),
|
|
110
|
+
value: valueCb(item)
|
|
111
|
+
};
|
|
112
|
+
});
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormService, deps: [{ token: DYNAMIC_FORM_FIELD_MAP_FN, optional: true }, { token: i1.FormBuilder }, { token: DynamicFormValidationsService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
116
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormService, providedIn: 'root' }); }
|
|
117
|
+
}
|
|
118
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormService, decorators: [{
|
|
119
|
+
type: Injectable,
|
|
120
|
+
args: [{
|
|
121
|
+
providedIn: 'root'
|
|
122
|
+
}]
|
|
123
|
+
}], ctorParameters: function () { return [{ type: undefined, decorators: [{
|
|
124
|
+
type: Inject,
|
|
125
|
+
args: [DYNAMIC_FORM_FIELD_MAP_FN]
|
|
126
|
+
}, {
|
|
127
|
+
type: Optional
|
|
128
|
+
}] }, { type: i1.FormBuilder }, { type: DynamicFormValidationsService }]; } });
|
|
129
|
+
|
|
130
|
+
class DynamicFormFieldBaseComponent {
|
|
131
|
+
get id() {
|
|
132
|
+
return this.model.id ?? this.model.name;
|
|
133
|
+
}
|
|
134
|
+
get control() {
|
|
135
|
+
const ctrl = this.group.get(this.model.name);
|
|
136
|
+
if (!ctrl) {
|
|
137
|
+
throw new Error(`Provided FormGroup does not contain a control with the name ${this.model.name}`);
|
|
138
|
+
}
|
|
139
|
+
return ctrl;
|
|
140
|
+
}
|
|
141
|
+
get isValid() {
|
|
142
|
+
return this.control.valid;
|
|
143
|
+
}
|
|
144
|
+
get isInvalid() {
|
|
145
|
+
return this.control.invalid;
|
|
146
|
+
}
|
|
147
|
+
onBlur(ev) {
|
|
148
|
+
this.blur.emit(ev);
|
|
149
|
+
}
|
|
150
|
+
onChange(ev) {
|
|
151
|
+
this.change.emit(ev);
|
|
152
|
+
}
|
|
153
|
+
onFocus(ev) {
|
|
154
|
+
this.focus.emit(ev);
|
|
155
|
+
}
|
|
156
|
+
resetControl() {
|
|
157
|
+
this.group.get(this.model.name)?.reset();
|
|
158
|
+
}
|
|
159
|
+
hasError(name) {
|
|
160
|
+
return this.control.hasError(name);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
class DynamicButtonComponent extends DynamicFormFieldBaseComponent {
|
|
165
|
+
onClick() {
|
|
166
|
+
this.model.onClick();
|
|
167
|
+
}
|
|
168
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicButtonComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
169
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DynamicButtonComponent, isStandalone: true, selector: "dynamic-button", inputs: { model: "model", group: "group" }, usesInheritance: true, ngImport: i0, template: "<ng-container *ngIf=\"model.raised else stroked\">\n <button mat-raised-button\n color=\"primary\"\n [id]=\"id\"\n (click)=\"onClick()\">\n <span>{{model.text}}</span>\n </button>\n</ng-container>\n\n<ng-template #stroked>\n <button mat-stroked-button\n color=\"primary\"\n [id]=\"id\"\n (click)=\"onClick()\">\n <span>{{model.text}}</span>\n </button>\n</ng-template>", dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }] }); }
|
|
170
|
+
}
|
|
171
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicButtonComponent, decorators: [{
|
|
172
|
+
type: Component,
|
|
173
|
+
args: [{ standalone: true, imports: [NgIf, MatButtonModule], selector: 'dynamic-button', template: "<ng-container *ngIf=\"model.raised else stroked\">\n <button mat-raised-button\n color=\"primary\"\n [id]=\"id\"\n (click)=\"onClick()\">\n <span>{{model.text}}</span>\n </button>\n</ng-container>\n\n<ng-template #stroked>\n <button mat-stroked-button\n color=\"primary\"\n [id]=\"id\"\n (click)=\"onClick()\">\n <span>{{model.text}}</span>\n </button>\n</ng-template>" }]
|
|
174
|
+
}], propDecorators: { model: [{
|
|
175
|
+
type: Input
|
|
176
|
+
}], group: [{
|
|
177
|
+
type: Input
|
|
178
|
+
}] } });
|
|
179
|
+
|
|
180
|
+
class DynamicFormFieldModel {
|
|
181
|
+
constructor(config) {
|
|
182
|
+
this.hidden = config.hidden ?? false;
|
|
183
|
+
this.id = config.id ?? config.name;
|
|
184
|
+
this.width = config.width ?? 100;
|
|
185
|
+
this.label = config.label ?? null;
|
|
186
|
+
this.name = config.name;
|
|
187
|
+
this.hint = config.hint ?? null;
|
|
188
|
+
this.validators = config.validators ?? [];
|
|
189
|
+
this.updateOn = config.updateOn ?? 'change';
|
|
190
|
+
this.relations = config.relations ?? null;
|
|
191
|
+
// Create a disabled Subject and Observable to change the state of the FormControl inside DynamicFormFieldComponent by subscribing to disabledChange
|
|
192
|
+
this.disabled$ = new BehaviorSubject(config.disabled ?? false);
|
|
193
|
+
this.disabledChange = this.disabled$.asObservable();
|
|
194
|
+
}
|
|
195
|
+
get disabled() {
|
|
196
|
+
return this.disabled$.getValue();
|
|
197
|
+
}
|
|
198
|
+
set disabled(disable) {
|
|
199
|
+
this.disabled$.next(disable);
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const DYNAMIC_FORM_FIELD_BUTTON = 'button';
|
|
204
|
+
class DynamicButton extends DynamicFormFieldModel {
|
|
205
|
+
constructor(config) {
|
|
206
|
+
super(config);
|
|
207
|
+
this.type = DYNAMIC_FORM_FIELD_BUTTON;
|
|
208
|
+
this.text = config.text ?? null;
|
|
209
|
+
this.raised = config.raised ?? false;
|
|
210
|
+
this.onClick = config.onClick;
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
class DynamicCheckboxComponent extends DynamicFormFieldBaseComponent {
|
|
215
|
+
constructor() {
|
|
216
|
+
super(...arguments);
|
|
217
|
+
this.blur = new EventEmitter();
|
|
218
|
+
this.change = new EventEmitter();
|
|
219
|
+
this.focus = new EventEmitter();
|
|
220
|
+
}
|
|
221
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicCheckboxComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
222
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DynamicCheckboxComponent, isStandalone: true, selector: "dynamic-checkbox", inputs: { model: "model", group: "group" }, outputs: { blur: "blur", change: "change", focus: "focus" }, usesInheritance: true, ngImport: i0, template: "<ng-container [formGroup]=\"group\">\n <mat-checkbox [checked]=\"model.checked\"\n [formControlName]=\"model.name\"\n [indeterminate]=\"model.indeterminate\"\n [labelPosition]=\"model.labelPosition\"\n [name]=\"model.name\"\n [id]=\"id\"\n (blur)=\"onBlur($event)\"\n (focus)=\"onFocus($event)\"\n (change)=\"onChange($event)\">\n\n <span class=\"checkbox-label\">{{model.label}}</span>\n </mat-checkbox>\n</ng-container>", dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i2.MatCheckbox, selector: "mat-checkbox", inputs: ["disableRipple", "color", "tabIndex"], exportAs: ["matCheckbox"] }] }); }
|
|
223
|
+
}
|
|
224
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicCheckboxComponent, decorators: [{
|
|
225
|
+
type: Component,
|
|
226
|
+
args: [{ selector: 'dynamic-checkbox', standalone: true, imports: [ReactiveFormsModule, MatCheckboxModule], template: "<ng-container [formGroup]=\"group\">\n <mat-checkbox [checked]=\"model.checked\"\n [formControlName]=\"model.name\"\n [indeterminate]=\"model.indeterminate\"\n [labelPosition]=\"model.labelPosition\"\n [name]=\"model.name\"\n [id]=\"id\"\n (blur)=\"onBlur($event)\"\n (focus)=\"onFocus($event)\"\n (change)=\"onChange($event)\">\n\n <span class=\"checkbox-label\">{{model.label}}</span>\n </mat-checkbox>\n</ng-container>" }]
|
|
227
|
+
}], propDecorators: { model: [{
|
|
228
|
+
type: Input
|
|
229
|
+
}], group: [{
|
|
230
|
+
type: Input
|
|
231
|
+
}], blur: [{
|
|
232
|
+
type: Output
|
|
233
|
+
}], change: [{
|
|
234
|
+
type: Output
|
|
235
|
+
}], focus: [{
|
|
236
|
+
type: Output
|
|
237
|
+
}] } });
|
|
238
|
+
|
|
239
|
+
class DynamicFormFieldValueModel extends DynamicFormFieldModel {
|
|
240
|
+
constructor(config) {
|
|
241
|
+
super(config);
|
|
242
|
+
this._defaultValue = config.defaultValue ?? null;
|
|
243
|
+
this._value = config.value ?? null;
|
|
244
|
+
this._value$ = new BehaviorSubject(this._value);
|
|
245
|
+
this.valueChanges = this._value$.asObservable();
|
|
246
|
+
}
|
|
247
|
+
get defaultValue() {
|
|
248
|
+
return this._defaultValue;
|
|
249
|
+
}
|
|
250
|
+
set defaultValue(val) {
|
|
251
|
+
this._defaultValue = val;
|
|
252
|
+
}
|
|
253
|
+
get value() {
|
|
254
|
+
return this._value$.getValue();
|
|
255
|
+
}
|
|
256
|
+
set value(val) {
|
|
257
|
+
this._value$.next(val);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const DYNAMIC_FORM_FIELD_CHECKBOX = 'checkbox';
|
|
262
|
+
class DynamicCheckbox extends DynamicFormFieldValueModel {
|
|
263
|
+
constructor(config) {
|
|
264
|
+
super(config);
|
|
265
|
+
this.type = DYNAMIC_FORM_FIELD_CHECKBOX;
|
|
266
|
+
this.value = config.value ?? false;
|
|
267
|
+
this.labelPosition = config.labelPosition ?? 'after';
|
|
268
|
+
this.indeterminate = config.indeterminate === true ? true : false;
|
|
269
|
+
}
|
|
270
|
+
get checked() {
|
|
271
|
+
return this.value ?? false;
|
|
272
|
+
}
|
|
273
|
+
set checked(checked) {
|
|
274
|
+
this.value = checked;
|
|
275
|
+
}
|
|
276
|
+
toggle() {
|
|
277
|
+
this.checked = !this.checked;
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
class DynamicInputComponent extends DynamicFormFieldBaseComponent {
|
|
282
|
+
constructor() {
|
|
283
|
+
super(...arguments);
|
|
284
|
+
this.blur = new EventEmitter();
|
|
285
|
+
this.change = new EventEmitter();
|
|
286
|
+
this.focus = new EventEmitter();
|
|
287
|
+
}
|
|
288
|
+
get valueCount() {
|
|
289
|
+
return this.input?.value ? this.input.value.length : 0;
|
|
290
|
+
}
|
|
291
|
+
get maxCountText() {
|
|
292
|
+
return `${this.valueCount} / ${this.model.maxLength}`;
|
|
293
|
+
}
|
|
294
|
+
get showClear() {
|
|
295
|
+
return !!this.control.value && !this.control.disabled;
|
|
296
|
+
}
|
|
297
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicInputComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
298
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DynamicInputComponent, isStandalone: true, selector: "dynamic-input", inputs: { model: "model", group: "group" }, outputs: { blur: "blur", change: "change", focus: "focus" }, viewQueries: [{ propertyName: "input", first: true, predicate: MatInput, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<mat-form-field [formGroup]=\"group\"\n [id]=\"id\"\n color=\"primary\">\n <mat-label *ngIf=\"model.label\">{{model.label}}</mat-label>\n\n <span matTextPrefix\n *ngIf=\"model.prefix\">{{model.prefix}}</span>\n\n <input matInput\n [type]=\"model.inputType\"\n [formControlName]=\"model.name\"\n [attr.min]=\"model.min\"\n [attr.max]=\"model.max\"\n [attr.minLength]=\"model.minLength\"\n [attr.maxLength]=\"model.maxLength\"\n [pattern]=\"model.pattern\"\n [autocomplete]=\"model.autocomplete\" />\n\n <button matSuffix\n mat-icon-button\n *ngIf=\"showClear\"\n (click)=\"resetControl()\">\n <mat-icon fontIcon=\"clear\"></mat-icon>\n </button>\n\n <mat-hint *ngIf=\"model.hint\"\n align=\"start\">{{model.hint}}</mat-hint>\n\n <mat-hint *ngIf=\"model.maxLength\"\n align=\"end\">{{maxCountText}}</mat-hint>\n\n <ng-container *ngFor=\"let validator of model.validators\"\n ngProjectAs=\"mat-error\">\n <mat-error *ngIf=\"hasError(validator.name)\">{{validator.message}}</mat-error>\n </ng-container>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.PatternValidator, selector: "[pattern][formControlName],[pattern][formControl],[pattern][ngModel]", inputs: ["pattern"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i1$2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i1$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: i1$2.MatPrefix, selector: "[matPrefix], [matIconPrefix], [matTextPrefix]", inputs: ["matTextPrefix"] }, { kind: "directive", type: i1$2.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i1$1.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i5.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }] }); }
|
|
299
|
+
}
|
|
300
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicInputComponent, decorators: [{
|
|
301
|
+
type: Component,
|
|
302
|
+
args: [{ selector: 'dynamic-input', standalone: true, imports: [NgIf, NgFor, ReactiveFormsModule, MatFormFieldModule, MatInputModule, MatButtonModule, MatIconModule], template: "<mat-form-field [formGroup]=\"group\"\n [id]=\"id\"\n color=\"primary\">\n <mat-label *ngIf=\"model.label\">{{model.label}}</mat-label>\n\n <span matTextPrefix\n *ngIf=\"model.prefix\">{{model.prefix}}</span>\n\n <input matInput\n [type]=\"model.inputType\"\n [formControlName]=\"model.name\"\n [attr.min]=\"model.min\"\n [attr.max]=\"model.max\"\n [attr.minLength]=\"model.minLength\"\n [attr.maxLength]=\"model.maxLength\"\n [pattern]=\"model.pattern\"\n [autocomplete]=\"model.autocomplete\" />\n\n <button matSuffix\n mat-icon-button\n *ngIf=\"showClear\"\n (click)=\"resetControl()\">\n <mat-icon fontIcon=\"clear\"></mat-icon>\n </button>\n\n <mat-hint *ngIf=\"model.hint\"\n align=\"start\">{{model.hint}}</mat-hint>\n\n <mat-hint *ngIf=\"model.maxLength\"\n align=\"end\">{{maxCountText}}</mat-hint>\n\n <ng-container *ngFor=\"let validator of model.validators\"\n ngProjectAs=\"mat-error\">\n <mat-error *ngIf=\"hasError(validator.name)\">{{validator.message}}</mat-error>\n </ng-container>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
|
|
303
|
+
}], propDecorators: { input: [{
|
|
304
|
+
type: ViewChild,
|
|
305
|
+
args: [MatInput, { static: true }]
|
|
306
|
+
}], model: [{
|
|
307
|
+
type: Input
|
|
308
|
+
}], group: [{
|
|
309
|
+
type: Input
|
|
310
|
+
}], blur: [{
|
|
311
|
+
type: Output
|
|
312
|
+
}], change: [{
|
|
313
|
+
type: Output
|
|
314
|
+
}], focus: [{
|
|
315
|
+
type: Output
|
|
316
|
+
}] } });
|
|
317
|
+
|
|
318
|
+
const DYNAMIC_FORM_FIELD_INPUT = 'input';
|
|
319
|
+
class DynamicInput extends DynamicFormFieldValueModel {
|
|
320
|
+
constructor(config) {
|
|
321
|
+
super(config);
|
|
322
|
+
this.type = DYNAMIC_FORM_FIELD_INPUT;
|
|
323
|
+
this.inputType = config.inputType ?? 'text';
|
|
324
|
+
this.max = config.max ?? null;
|
|
325
|
+
this.min = config.min ?? null;
|
|
326
|
+
this.maxLength = typeof config.maxLength === 'number' ? config.maxLength : null;
|
|
327
|
+
this.minLength = typeof config.minLength === 'number' ? config.minLength : null;
|
|
328
|
+
this.step = config.step ?? null;
|
|
329
|
+
this.pattern = config.pattern ?? '';
|
|
330
|
+
this.autocomplete = config.autocomplete ?? 'off';
|
|
331
|
+
this.prefix = config.prefix ?? null;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
class DynamicReadonlyComponent extends DynamicFormFieldBaseComponent {
|
|
336
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicReadonlyComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
337
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DynamicReadonlyComponent, isStandalone: true, selector: "dynamic-readonly", inputs: { model: "model", group: "group" }, usesInheritance: true, ngImport: i0, template: "<div class=\"dynamic-form-field-readonly\"\n [formGroup]=\"group\"\n [id]=\"id\">\n <div class=\"label\">{{model.label}}</div>\n <span>{{model.value}}</span>\n</div>", styles: [".dynamic-form-field-readonly{width:100%;margin:8px 0;color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, .87))}.dynamic-form-field-readonly .label{font-size:var(--mdc-typography-body2-font-size, 14px);line-height:var(--mdc-typography-body2-line-height, 20px);margin-bottom:8px}\n"], dependencies: [{ kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }] }); }
|
|
338
|
+
}
|
|
339
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicReadonlyComponent, decorators: [{
|
|
340
|
+
type: Component,
|
|
341
|
+
args: [{ standalone: true, imports: [ReactiveFormsModule], selector: 'dynamic-readonly', template: "<div class=\"dynamic-form-field-readonly\"\n [formGroup]=\"group\"\n [id]=\"id\">\n <div class=\"label\">{{model.label}}</div>\n <span>{{model.value}}</span>\n</div>", styles: [".dynamic-form-field-readonly{width:100%;margin:8px 0;color:var(--mdc-theme-text-primary-on-background, rgba(0, 0, 0, .87))}.dynamic-form-field-readonly .label{font-size:var(--mdc-typography-body2-font-size, 14px);line-height:var(--mdc-typography-body2-line-height, 20px);margin-bottom:8px}\n"] }]
|
|
342
|
+
}], propDecorators: { model: [{
|
|
343
|
+
type: Input
|
|
344
|
+
}], group: [{
|
|
345
|
+
type: Input
|
|
346
|
+
}] } });
|
|
347
|
+
|
|
348
|
+
const DYNAMIC_FORM_FIELD_READONLY = 'readonly';
|
|
349
|
+
class DynamicReadonly extends DynamicFormFieldValueModel {
|
|
350
|
+
constructor(config) {
|
|
351
|
+
super(config);
|
|
352
|
+
this.type = DYNAMIC_FORM_FIELD_READONLY;
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
class DynamicSelectComponent extends DynamicFormFieldBaseComponent {
|
|
357
|
+
constructor() {
|
|
358
|
+
super(...arguments);
|
|
359
|
+
this.blur = new EventEmitter();
|
|
360
|
+
this.change = new EventEmitter();
|
|
361
|
+
this.focus = new EventEmitter();
|
|
362
|
+
}
|
|
363
|
+
trackByFn(index, option) {
|
|
364
|
+
return option.value;
|
|
365
|
+
}
|
|
366
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicSelectComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
367
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DynamicSelectComponent, isStandalone: true, selector: "dynamic-select", inputs: { model: "model", group: "group" }, outputs: { blur: "blur", change: "change", focus: "focus" }, usesInheritance: true, ngImport: i0, template: "<mat-form-field [formGroup]=\"group\"\n [id]=\"id\"\n color=\"primary\">\n <mat-label>{{model.label}}</mat-label>\n\n <!-- Template for select without grouped options -->\n <ng-container *ngIf=\"model.options$ | async as options\">\n <ng-container *ngIf=\"!model.native else nativeSelect\">\n <mat-select [formControlName]=\"model.name\"\n [multiple]=\"model.multiple\">\n <mat-option *ngFor=\"let option of options; trackBy: trackByFn\"\n [value]=\"option.value\">\n {{option.label}}\n </mat-option>\n </mat-select>\n </ng-container>\n\n <ng-template #nativeSelect>\n <select matNativeControl>\n <option *ngFor=\"let option of options\"\n [value]=\"option.value\">\n {{option.label}}\n </option>\n </select>\n </ng-template>\n </ng-container>\n\n <!-- Template for select with grouped options -->\n <ng-container *ngIf=\"model.groupedOptions$ | async as groupedOptions\">\n <ng-container *ngIf=\"!model.native else nativeSelectGrouped\">\n <mat-select [formControlName]=\"model.name\">\n <mat-optgroup *ngFor=\"let group of groupedOptions\"\n [label]=\"group.name\">\n <mat-option *ngFor=\"let option of group.options; trackBy: trackByFn\"\n [value]=\"option.value\">\n {{option.label}}\n </mat-option>\n </mat-optgroup>\n </mat-select>\n </ng-container>\n\n <ng-template #nativeSelectGrouped>\n <select matNativeControl>\n <optgroup *ngFor=\"let group of groupedOptions\"\n [label]=\"group.name\">\n <option *ngFor=\"let option of group.options\"\n [value]=\"option.value\">\n {{option.label}}\n </option>\n </optgroup>\n </select>\n </ng-template>\n </ng-container>\n\n <mat-hint *ngIf=\"model.hint\"\n align=\"start\">{{model.hint}}</mat-hint>\n\n <ng-container *ngFor=\"let validator of model.validators\"\n ngProjectAs=\"mat-error\">\n <mat-error *ngIf=\"hasError(validator.name)\">{{validator.message}}</mat-error>\n </ng-container>\n</mat-form-field>", styles: ["mat-form-field{width:100%}mat-option{padding-top:8px;padding-bottom:8px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i1$2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i1$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "ngmodule", type: MatSelectModule }, { kind: "component", type: i3$1.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i4.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i4.MatOptgroup, selector: "mat-optgroup", inputs: ["disabled"], exportAs: ["matOptgroup"] }, { kind: "ngmodule", type: MatOptionModule }, { kind: "pipe", type: AsyncPipe, name: "async" }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }] }); }
|
|
368
|
+
}
|
|
369
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicSelectComponent, decorators: [{
|
|
370
|
+
type: Component,
|
|
371
|
+
args: [{ standalone: true, imports: [NgIf, NgFor, MatFormFieldModule, ReactiveFormsModule, MatSelectModule, MatOptionModule, AsyncPipe, MatInputModule], selector: 'dynamic-select', template: "<mat-form-field [formGroup]=\"group\"\n [id]=\"id\"\n color=\"primary\">\n <mat-label>{{model.label}}</mat-label>\n\n <!-- Template for select without grouped options -->\n <ng-container *ngIf=\"model.options$ | async as options\">\n <ng-container *ngIf=\"!model.native else nativeSelect\">\n <mat-select [formControlName]=\"model.name\"\n [multiple]=\"model.multiple\">\n <mat-option *ngFor=\"let option of options; trackBy: trackByFn\"\n [value]=\"option.value\">\n {{option.label}}\n </mat-option>\n </mat-select>\n </ng-container>\n\n <ng-template #nativeSelect>\n <select matNativeControl>\n <option *ngFor=\"let option of options\"\n [value]=\"option.value\">\n {{option.label}}\n </option>\n </select>\n </ng-template>\n </ng-container>\n\n <!-- Template for select with grouped options -->\n <ng-container *ngIf=\"model.groupedOptions$ | async as groupedOptions\">\n <ng-container *ngIf=\"!model.native else nativeSelectGrouped\">\n <mat-select [formControlName]=\"model.name\">\n <mat-optgroup *ngFor=\"let group of groupedOptions\"\n [label]=\"group.name\">\n <mat-option *ngFor=\"let option of group.options; trackBy: trackByFn\"\n [value]=\"option.value\">\n {{option.label}}\n </mat-option>\n </mat-optgroup>\n </mat-select>\n </ng-container>\n\n <ng-template #nativeSelectGrouped>\n <select matNativeControl>\n <optgroup *ngFor=\"let group of groupedOptions\"\n [label]=\"group.name\">\n <option *ngFor=\"let option of group.options\"\n [value]=\"option.value\">\n {{option.label}}\n </option>\n </optgroup>\n </select>\n </ng-template>\n </ng-container>\n\n <mat-hint *ngIf=\"model.hint\"\n align=\"start\">{{model.hint}}</mat-hint>\n\n <ng-container *ngFor=\"let validator of model.validators\"\n ngProjectAs=\"mat-error\">\n <mat-error *ngIf=\"hasError(validator.name)\">{{validator.message}}</mat-error>\n </ng-container>\n</mat-form-field>", styles: ["mat-form-field{width:100%}mat-option{padding-top:8px;padding-bottom:8px}\n"] }]
|
|
372
|
+
}], propDecorators: { model: [{
|
|
373
|
+
type: Input
|
|
374
|
+
}], group: [{
|
|
375
|
+
type: Input
|
|
376
|
+
}], blur: [{
|
|
377
|
+
type: Output
|
|
378
|
+
}], change: [{
|
|
379
|
+
type: Output
|
|
380
|
+
}], focus: [{
|
|
381
|
+
type: Output
|
|
382
|
+
}] } });
|
|
383
|
+
|
|
384
|
+
/**
|
|
385
|
+
* Base class for any DynamicFormField with options (e.g. DynamicSelect or DynamicAutocomplete)
|
|
386
|
+
*/
|
|
387
|
+
class DynamicFormFieldOptionModel extends DynamicFormFieldValueModel {
|
|
388
|
+
constructor(config) {
|
|
389
|
+
super(config);
|
|
390
|
+
this._options = [];
|
|
391
|
+
this._groupedOptions = [];
|
|
392
|
+
if (!config.options && !config.groupedOptions) {
|
|
393
|
+
console.error(`No options or groupedOptions provided for ${this.name}`);
|
|
394
|
+
}
|
|
395
|
+
if (config.options) {
|
|
396
|
+
this.options$ = this.setOptions(config.options);
|
|
397
|
+
}
|
|
398
|
+
else if (config.groupedOptions) {
|
|
399
|
+
this.groupedOptions$ = this.setGroupedOptions(config.groupedOptions);
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
setOptions(options) {
|
|
403
|
+
if (Array.isArray(options)) {
|
|
404
|
+
this._options = options;
|
|
405
|
+
return of(this._options);
|
|
406
|
+
}
|
|
407
|
+
if (isObservable(options)) {
|
|
408
|
+
return options.pipe(map((o) => {
|
|
409
|
+
this._options = o;
|
|
410
|
+
return this._options;
|
|
411
|
+
}));
|
|
412
|
+
}
|
|
413
|
+
return of([]);
|
|
414
|
+
}
|
|
415
|
+
setGroupedOptions(groupedOptions) {
|
|
416
|
+
if (Array.isArray(groupedOptions)) {
|
|
417
|
+
this._groupedOptions = groupedOptions;
|
|
418
|
+
return of(this._groupedOptions);
|
|
419
|
+
}
|
|
420
|
+
if (isObservable(groupedOptions)) {
|
|
421
|
+
return groupedOptions.pipe(map((o) => {
|
|
422
|
+
this._groupedOptions = o;
|
|
423
|
+
return this._groupedOptions;
|
|
424
|
+
}));
|
|
425
|
+
}
|
|
426
|
+
return of([]);
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
const DYNAMIC_FORM_FIELD_SELECT = 'select';
|
|
431
|
+
class DynamicSelect extends DynamicFormFieldOptionModel {
|
|
432
|
+
constructor(config) {
|
|
433
|
+
super(config);
|
|
434
|
+
this.type = DYNAMIC_FORM_FIELD_SELECT;
|
|
435
|
+
this.native = config.native ?? false;
|
|
436
|
+
this.multiple = config.multiple ?? false;
|
|
437
|
+
}
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
class DynamicTextareaComponent extends DynamicFormFieldBaseComponent {
|
|
441
|
+
constructor() {
|
|
442
|
+
super(...arguments);
|
|
443
|
+
this.blur = new EventEmitter();
|
|
444
|
+
this.change = new EventEmitter();
|
|
445
|
+
this.focus = new EventEmitter();
|
|
446
|
+
}
|
|
447
|
+
get valueCount() {
|
|
448
|
+
return this.textarea?.value ? this.textarea.value.length : 0;
|
|
449
|
+
}
|
|
450
|
+
get maxCountText() {
|
|
451
|
+
return `${this.valueCount} / ${this.model.maxLength}`;
|
|
452
|
+
}
|
|
453
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicTextareaComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
454
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DynamicTextareaComponent, isStandalone: true, selector: "dynamic-textarea", inputs: { model: "model", group: "group" }, outputs: { blur: "blur", change: "change", focus: "focus" }, viewQueries: [{ propertyName: "textarea", first: true, predicate: MatInput, descendants: true, static: true }], usesInheritance: true, ngImport: i0, template: "<mat-form-field [formGroup]=\"group\"\n [id]=\"id\"\n color=\"primary\">\n <mat-label *ngIf=\"model.label\">{{model.label}}</mat-label>\n\n <textarea matInput\n [cdkTextareaAutosize]=\"model.resize\"\n [cdkAutosizeMinRows]=\"model.rows\"\n [cdkAutosizeMaxRows]=\"model.resizeMaxRows\"\n [id]=\"id\"\n [formControlName]=\"model.name\"\n [attr.minLength]=\"model.minLength\"\n [attr.maxLength]=\"model.maxLength\"\n [rows]=\"model.rows\"\n [autocomplete]=\"model.autocomplete\">\n </textarea>\n\n <mat-hint *ngIf=\"model.hint\"\n align=\"start\">{{model.hint}}</mat-hint>\n\n <mat-hint *ngIf=\"model.maxLength\"\n align=\"end\">{{maxCountText}}</mat-hint>\n\n <ng-container *ngFor=\"let validator of model.validators\"\n ngProjectAs=\"mat-error\">\n <mat-error *ngIf=\"hasError(validator.name)\">{{validator.message}}</mat-error>\n </ng-container>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "ngmodule", type: MatFormFieldModule }, { kind: "component", type: i1$2.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i1$2.MatLabel, selector: "mat-label" }, { kind: "directive", type: i1$2.MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "directive", type: i1$2.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i3.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "directive", type: i3$2.CdkTextareaAutosize, selector: "textarea[cdkTextareaAutosize]", inputs: ["cdkAutosizeMinRows", "cdkAutosizeMaxRows", "cdkTextareaAutosize", "placeholder"], exportAs: ["cdkTextareaAutosize"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }] }); }
|
|
455
|
+
}
|
|
456
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicTextareaComponent, decorators: [{
|
|
457
|
+
type: Component,
|
|
458
|
+
args: [{ standalone: true, imports: [NgIf, NgFor, MatFormFieldModule, MatInputModule, ReactiveFormsModule], selector: 'dynamic-textarea', template: "<mat-form-field [formGroup]=\"group\"\n [id]=\"id\"\n color=\"primary\">\n <mat-label *ngIf=\"model.label\">{{model.label}}</mat-label>\n\n <textarea matInput\n [cdkTextareaAutosize]=\"model.resize\"\n [cdkAutosizeMinRows]=\"model.rows\"\n [cdkAutosizeMaxRows]=\"model.resizeMaxRows\"\n [id]=\"id\"\n [formControlName]=\"model.name\"\n [attr.minLength]=\"model.minLength\"\n [attr.maxLength]=\"model.maxLength\"\n [rows]=\"model.rows\"\n [autocomplete]=\"model.autocomplete\">\n </textarea>\n\n <mat-hint *ngIf=\"model.hint\"\n align=\"start\">{{model.hint}}</mat-hint>\n\n <mat-hint *ngIf=\"model.maxLength\"\n align=\"end\">{{maxCountText}}</mat-hint>\n\n <ng-container *ngFor=\"let validator of model.validators\"\n ngProjectAs=\"mat-error\">\n <mat-error *ngIf=\"hasError(validator.name)\">{{validator.message}}</mat-error>\n </ng-container>\n</mat-form-field>", styles: ["mat-form-field{width:100%}\n"] }]
|
|
459
|
+
}], propDecorators: { textarea: [{
|
|
460
|
+
type: ViewChild,
|
|
461
|
+
args: [MatInput, { static: true }]
|
|
462
|
+
}], model: [{
|
|
463
|
+
type: Input
|
|
464
|
+
}], group: [{
|
|
465
|
+
type: Input
|
|
466
|
+
}], blur: [{
|
|
467
|
+
type: Output
|
|
468
|
+
}], change: [{
|
|
469
|
+
type: Output
|
|
470
|
+
}], focus: [{
|
|
471
|
+
type: Output
|
|
472
|
+
}] } });
|
|
473
|
+
|
|
474
|
+
const DYNAMIC_FORM_FIELD_TEXTAREA = 'textarea';
|
|
475
|
+
class DynamicTextarea extends DynamicFormFieldValueModel {
|
|
476
|
+
constructor(config) {
|
|
477
|
+
super(config);
|
|
478
|
+
this.type = DYNAMIC_FORM_FIELD_TEXTAREA;
|
|
479
|
+
this.minLength = config.minLength ?? 0;
|
|
480
|
+
this.maxLength = config.minLength ?? null;
|
|
481
|
+
this.autocomplete = config.autocomplete ?? 'off';
|
|
482
|
+
this.rows = config.rows ?? 3;
|
|
483
|
+
this.resize = config.resize ?? true;
|
|
484
|
+
this.resizeMaxRows = config.resizeMaxRows ?? null;
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
class DynamicFormValidators {
|
|
489
|
+
/**
|
|
490
|
+
* Default required validator, the control must contain a value
|
|
491
|
+
* @param msg
|
|
492
|
+
*/
|
|
493
|
+
static required(msg) {
|
|
494
|
+
const message = msg ?? 'Dit veld is verplicht';
|
|
495
|
+
return { name: 'required', validator: Validators.required, message };
|
|
496
|
+
}
|
|
497
|
+
/**
|
|
498
|
+
* Ddefault requiredTrue validator, the value of the control has to be true
|
|
499
|
+
* @param msg
|
|
500
|
+
*/
|
|
501
|
+
static requiredTrue(msg) {
|
|
502
|
+
const message = msg ?? 'Dit veld is verplicht';
|
|
503
|
+
return { name: 'requiredTrue', validator: Validators.requiredTrue, message };
|
|
504
|
+
}
|
|
505
|
+
/**
|
|
506
|
+
* Default min validator, the value has to be greater or equal than the the provided number
|
|
507
|
+
* @param min number
|
|
508
|
+
* @param msg
|
|
509
|
+
*/
|
|
510
|
+
static min(min, msg) {
|
|
511
|
+
const message = msg ?? `Minimum is ${min}`;
|
|
512
|
+
return { name: 'min', validator: Validators.min(min), message };
|
|
513
|
+
}
|
|
514
|
+
/**
|
|
515
|
+
* Default max validator, the value has to be less or equal than the the provided number
|
|
516
|
+
* @param max number
|
|
517
|
+
* @param msg
|
|
518
|
+
*/
|
|
519
|
+
static max(max, msg) {
|
|
520
|
+
const message = msg ?? `Maximum is ${max}`;
|
|
521
|
+
return { name: 'max', validator: Validators.max(max), message };
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Default minLength validator, the value has to contain a minimum amount of characters
|
|
525
|
+
* @param min number
|
|
526
|
+
* @param msg
|
|
527
|
+
*/
|
|
528
|
+
static minLength(min, msg) {
|
|
529
|
+
const message = msg ?? `Minimaal ${min} tekens`;
|
|
530
|
+
return { name: 'minLength', validator: Validators.min(min), message };
|
|
531
|
+
}
|
|
532
|
+
/**
|
|
533
|
+
* Default maxLength validator, the value has to contain a maximum amount of characters
|
|
534
|
+
* @param max number
|
|
535
|
+
* @param msg
|
|
536
|
+
*/
|
|
537
|
+
static maxLength(max, msg) {
|
|
538
|
+
const message = msg ?? `Maximaal ${max} tekens`;
|
|
539
|
+
return { name: 'maxLength', validator: Validators.max(max), message };
|
|
540
|
+
}
|
|
541
|
+
/**
|
|
542
|
+
* Ddefault email validator, the value of the control has to be a valid email address
|
|
543
|
+
* @param msg
|
|
544
|
+
*/
|
|
545
|
+
static email(msg) {
|
|
546
|
+
const message = msg ?? 'Geen geldig emailadres';
|
|
547
|
+
return { name: 'email', validator: Validators.email, message };
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Default pattern validator, the value of the control has to match the provided pattern
|
|
551
|
+
* @param pattern: string | RegExp
|
|
552
|
+
* @param msg
|
|
553
|
+
*/
|
|
554
|
+
static pattern(pattern, msg) {
|
|
555
|
+
const message = msg ?? 'Geen geldige invoer';
|
|
556
|
+
return { name: 'pattern', validator: Validators.pattern(pattern), message };
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
var RelationActionType;
|
|
561
|
+
(function (RelationActionType) {
|
|
562
|
+
RelationActionType["DISABLED"] = "DISABLED";
|
|
563
|
+
RelationActionType["ENABLED"] = "ENABLED";
|
|
564
|
+
RelationActionType["HIDDEN"] = "HIDDEN";
|
|
565
|
+
RelationActionType["VISIBLE"] = "VISIBLE";
|
|
566
|
+
RelationActionType["REQUIRED"] = "REQUIRED";
|
|
567
|
+
RelationActionType["OPTIONAL"] = "OPTIONAL";
|
|
568
|
+
})(RelationActionType || (RelationActionType = {}));
|
|
569
|
+
var RelationOperator;
|
|
570
|
+
(function (RelationOperator) {
|
|
571
|
+
RelationOperator["AND"] = "AND";
|
|
572
|
+
RelationOperator["OR"] = "OR";
|
|
573
|
+
})(RelationOperator || (RelationOperator = {}));
|
|
574
|
+
const DISABLE_ACTION = {
|
|
575
|
+
type: RelationActionType.DISABLED,
|
|
576
|
+
reversedType: RelationActionType.ENABLED,
|
|
577
|
+
change(hasMatch, model) {
|
|
578
|
+
model.disabled = hasMatch;
|
|
579
|
+
}
|
|
580
|
+
};
|
|
581
|
+
const HIDDEN_ACTION = {
|
|
582
|
+
type: RelationActionType.HIDDEN,
|
|
583
|
+
reversedType: RelationActionType.VISIBLE,
|
|
584
|
+
change(hasMatch, model) {
|
|
585
|
+
model.hidden = hasMatch;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
const REQUIRED_ACTION = {
|
|
589
|
+
type: RelationActionType.REQUIRED,
|
|
590
|
+
reversedType: RelationActionType.OPTIONAL,
|
|
591
|
+
change(hasMatch, model, control, injector) {
|
|
592
|
+
const hasRequiredValidation = !!model.validators.find((f) => f.name === 'required');
|
|
593
|
+
let validators;
|
|
594
|
+
if (hasMatch) {
|
|
595
|
+
validators = hasRequiredValidation ? model.validators : [...model.validators, DynamicFormValidators.required()];
|
|
596
|
+
}
|
|
597
|
+
else {
|
|
598
|
+
validators = model.validators.filter((f) => f.name === 'required');
|
|
599
|
+
}
|
|
600
|
+
injector.get(DynamicFormValidationsService).updateValidators(validators, control);
|
|
601
|
+
}
|
|
602
|
+
};
|
|
603
|
+
const RELATION_ACTIONS = [DISABLE_ACTION, HIDDEN_ACTION, REQUIRED_ACTION];
|
|
604
|
+
|
|
605
|
+
class DynamicFormRelationsService {
|
|
606
|
+
constructor() {
|
|
607
|
+
this._injector = inject(Injector);
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* Get an object with all FormField the provided model has a relation with
|
|
611
|
+
* @param model
|
|
612
|
+
* @param group
|
|
613
|
+
* @returns
|
|
614
|
+
*/
|
|
615
|
+
findRelatedFormField(model, group) {
|
|
616
|
+
const conditionReducer = (controls, condition) => {
|
|
617
|
+
const control = group.get(condition.fieldName);
|
|
618
|
+
if (!control) {
|
|
619
|
+
console.warn(`No related form control with the name ${condition.fieldName} found`);
|
|
620
|
+
return controls;
|
|
621
|
+
}
|
|
622
|
+
controls[condition.fieldName] = control;
|
|
623
|
+
return controls;
|
|
624
|
+
};
|
|
625
|
+
const relationsReducer = (controls, relation) => {
|
|
626
|
+
return relation.conditions.reduce(conditionReducer, controls);
|
|
627
|
+
};
|
|
628
|
+
return model.relations.reduce(relationsReducer, {});
|
|
629
|
+
}
|
|
630
|
+
getRelationSubscriptions(relatedFormControls, model, control) {
|
|
631
|
+
const subs = [];
|
|
632
|
+
// Subscribe to value changes of all FormControls, provide the current value inside the startWith
|
|
633
|
+
Object.values(relatedFormControls).forEach((relatedControl) => {
|
|
634
|
+
subs.push(relatedControl.valueChanges.pipe(startWith(relatedControl.value), distinctUntilChanged()).subscribe(() => {
|
|
635
|
+
model.relations.forEach((relation) => {
|
|
636
|
+
// Find the RelationAction object based on the actionType passed inside the DynamicFormConfig
|
|
637
|
+
const action = RELATION_ACTIONS.find((action) => relation.actionType === action.type || relation.actionType === action.reversedType);
|
|
638
|
+
if (action) {
|
|
639
|
+
const shouldTrigger = this.checkRelationCondition(relation, relatedFormControls, action);
|
|
640
|
+
action.change(shouldTrigger, model, control, this._injector);
|
|
641
|
+
}
|
|
642
|
+
});
|
|
643
|
+
}));
|
|
644
|
+
});
|
|
645
|
+
return subs;
|
|
646
|
+
}
|
|
647
|
+
/**
|
|
648
|
+
* Check the conditions inside the relations
|
|
649
|
+
* @param relation
|
|
650
|
+
* @param relatedControl
|
|
651
|
+
* @param action
|
|
652
|
+
* @returns
|
|
653
|
+
*/
|
|
654
|
+
checkRelationCondition(relation, relatedControls, action) {
|
|
655
|
+
// Default operator is AND, meaning all conditions should return true before the provided action is triggered.
|
|
656
|
+
// In the case of a reversed type, the return value whould be false.
|
|
657
|
+
const operator = relation.operator ?? RelationOperator.AND;
|
|
658
|
+
// Use a reducer to map all conditions to a single boolean value to decide if we want to trigger the provided action type
|
|
659
|
+
const reducer = (isMatch, condition, index) => {
|
|
660
|
+
// Find the FormControl of the related field
|
|
661
|
+
let relatedControl;
|
|
662
|
+
for (const [fieldName, control] of Object.entries(relatedControls)) {
|
|
663
|
+
if (fieldName === condition.fieldName) {
|
|
664
|
+
relatedControl = control;
|
|
665
|
+
break;
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
if (!relatedControl)
|
|
669
|
+
return false;
|
|
670
|
+
// Using the 'normal' type should return true when the condition matches
|
|
671
|
+
if (relation.actionType === action.type) {
|
|
672
|
+
// Shortcut to false when a previous condition check was resolved as false
|
|
673
|
+
if (index > 0 && operator === RelationOperator.AND && !isMatch)
|
|
674
|
+
return false;
|
|
675
|
+
// Shortcut to true when a previous condition check was resolved as true
|
|
676
|
+
if (index > 0 && operator === RelationOperator.OR && isMatch)
|
|
677
|
+
return true;
|
|
678
|
+
return condition.value(relatedControl.value);
|
|
679
|
+
}
|
|
680
|
+
// Using the reversed type should return false when the condition matches, because we want to the opposite of the configured change Function
|
|
681
|
+
if (relation.actionType === action.reversedType) {
|
|
682
|
+
// Shortcut to true when a previous condition check was resolved as true
|
|
683
|
+
if (index > 0 && operator === RelationOperator.AND && isMatch)
|
|
684
|
+
return true;
|
|
685
|
+
// Shortcut to false when a previous condition check was resolved as false
|
|
686
|
+
if (index > 0 && operator === RelationOperator.OR && !isMatch)
|
|
687
|
+
return false;
|
|
688
|
+
return !condition.value(relatedControl.value);
|
|
689
|
+
}
|
|
690
|
+
return false;
|
|
691
|
+
};
|
|
692
|
+
return relation.conditions.reduce(reducer, false);
|
|
693
|
+
}
|
|
694
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormRelationsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
695
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormRelationsService, providedIn: 'root' }); }
|
|
696
|
+
}
|
|
697
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormRelationsService, decorators: [{
|
|
698
|
+
type: Injectable,
|
|
699
|
+
args: [{
|
|
700
|
+
providedIn: 'root'
|
|
701
|
+
}]
|
|
702
|
+
}] });
|
|
703
|
+
|
|
704
|
+
class DynamicFormFieldComponent {
|
|
705
|
+
constructor() {
|
|
706
|
+
this._subs = new Subscription();
|
|
707
|
+
this.dynamicFormService = inject(DynamicFormService);
|
|
708
|
+
this.relationService = inject(DynamicFormRelationsService);
|
|
709
|
+
}
|
|
710
|
+
/** Get the instance of a control component using the injected custom method or local method */
|
|
711
|
+
get componentType() {
|
|
712
|
+
return this.dynamicFormService.getCustomControlComponentType(this.model) || this.getControlComponentType();
|
|
713
|
+
}
|
|
714
|
+
ngOnInit() {
|
|
715
|
+
if (this.group) {
|
|
716
|
+
this._control = this.group.get(this.model.name);
|
|
717
|
+
this.createFormControlComponent();
|
|
718
|
+
this.setSubscriptions();
|
|
719
|
+
}
|
|
720
|
+
}
|
|
721
|
+
ngOnDestroy() {
|
|
722
|
+
this._subs.unsubscribe();
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Finds the instance of a control component by type
|
|
726
|
+
* @returns
|
|
727
|
+
*/
|
|
728
|
+
getControlComponentType() {
|
|
729
|
+
switch (this.model.type) {
|
|
730
|
+
case DYNAMIC_FORM_FIELD_CHECKBOX:
|
|
731
|
+
return DynamicCheckboxComponent;
|
|
732
|
+
case DYNAMIC_FORM_FIELD_INPUT:
|
|
733
|
+
return DynamicInputComponent;
|
|
734
|
+
case DYNAMIC_FORM_FIELD_TEXTAREA:
|
|
735
|
+
return DynamicTextareaComponent;
|
|
736
|
+
case DYNAMIC_FORM_FIELD_READONLY:
|
|
737
|
+
return DynamicReadonlyComponent;
|
|
738
|
+
case DYNAMIC_FORM_FIELD_SELECT:
|
|
739
|
+
return DynamicSelectComponent;
|
|
740
|
+
case DYNAMIC_FORM_FIELD_BUTTON:
|
|
741
|
+
return DynamicButtonComponent;
|
|
742
|
+
default:
|
|
743
|
+
console.warn(`Model of type 'dynamic-${this.model.type}' is not implemented yet. Add this type to dynamic-form-field.component.ts to add support`);
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
createFormControlComponent() {
|
|
748
|
+
const component = this.componentType;
|
|
749
|
+
if (component != null) {
|
|
750
|
+
let componentRef = this.componentViewContainer.createComponent(component);
|
|
751
|
+
const componentInstance = componentRef.instance;
|
|
752
|
+
componentInstance.group = this.group;
|
|
753
|
+
componentInstance.model = this.model;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
/**
|
|
757
|
+
* Setup all necessary subscriptions of the FormControl
|
|
758
|
+
*/
|
|
759
|
+
setSubscriptions() {
|
|
760
|
+
const model = this.model;
|
|
761
|
+
// Subscribe to the value change inside the control to chagne the value inside the model as well
|
|
762
|
+
this._subs.add(this._control.valueChanges.subscribe((value) => this.onValueChange(value)));
|
|
763
|
+
// Subscribe to the disabled change inside the model to change the disabled state of the FormControl
|
|
764
|
+
this._subs.add(model.disabledChange.subscribe((disabled) => this.onDisabledChange(disabled)));
|
|
765
|
+
// Setup subscriptions for any possible relation
|
|
766
|
+
if (this.model.relations?.length) {
|
|
767
|
+
this.setUpRelations();
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
/**
|
|
771
|
+
* Set up all relations of the current model
|
|
772
|
+
*/
|
|
773
|
+
setUpRelations() {
|
|
774
|
+
// Array of all FormControls the current model has a relation to
|
|
775
|
+
const relatedFormControls = this.relationService.findRelatedFormField(this.model, this.group);
|
|
776
|
+
const subs = this.relationService.getRelationSubscriptions(relatedFormControls, this.model, this._control);
|
|
777
|
+
// Add all relations as subscription to the main Subscription object
|
|
778
|
+
subs.forEach((sub) => this._subs.add(sub));
|
|
779
|
+
}
|
|
780
|
+
/**
|
|
781
|
+
* Fired when the value changes of the control and updates the value inside the model
|
|
782
|
+
* @param value
|
|
783
|
+
*/
|
|
784
|
+
onValueChange(value) {
|
|
785
|
+
if (this.model instanceof DynamicFormFieldValueModel && this.model.value !== value) {
|
|
786
|
+
this.model.value = value;
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
/**
|
|
790
|
+
* Enables/disabled the control based on the provided parameter.
|
|
791
|
+
* Is fired when disabled state is changed inside the model and should not be directly used outside this component.
|
|
792
|
+
* @param disabled
|
|
793
|
+
*/
|
|
794
|
+
onDisabledChange(disabled) {
|
|
795
|
+
disabled ? this._control.disable() : this._control.enable();
|
|
796
|
+
}
|
|
797
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormFieldComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
798
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DynamicFormFieldComponent, isStandalone: true, selector: "dynamic-form-field", inputs: { model: "model", group: "group" }, viewQueries: [{ propertyName: "componentViewContainer", first: true, predicate: ["componentViewContainer"], descendants: true, read: ViewContainerRef, static: true }], ngImport: i0, template: "<div [formGroup]=\"group\"\n [ngClass]=\"['dynamic-form-field-container', 'dynamic-form-field-' + model.type]\">\n <ng-container #componentViewContainer></ng-container>\n</div>", dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
799
|
+
}
|
|
800
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormFieldComponent, decorators: [{
|
|
801
|
+
type: Component,
|
|
802
|
+
args: [{ standalone: true, imports: [NgClass, ReactiveFormsModule], selector: 'dynamic-form-field', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div [formGroup]=\"group\"\n [ngClass]=\"['dynamic-form-field-container', 'dynamic-form-field-' + model.type]\">\n <ng-container #componentViewContainer></ng-container>\n</div>" }]
|
|
803
|
+
}], propDecorators: { componentViewContainer: [{
|
|
804
|
+
type: ViewChild,
|
|
805
|
+
args: ['componentViewContainer', { read: ViewContainerRef, static: true }]
|
|
806
|
+
}], model: [{
|
|
807
|
+
type: Input
|
|
808
|
+
}], group: [{
|
|
809
|
+
type: Input
|
|
810
|
+
}] } });
|
|
811
|
+
|
|
812
|
+
class DynamicFormComponent {
|
|
813
|
+
constructor() {
|
|
814
|
+
this.ready = new EventEmitter();
|
|
815
|
+
this.dynamicFormService = inject(DynamicFormService);
|
|
816
|
+
}
|
|
817
|
+
/**
|
|
818
|
+
* Get the formConfig as flat array.
|
|
819
|
+
*/
|
|
820
|
+
get flatFormConfig() {
|
|
821
|
+
return this.formConfig.reduce((acc, curr) => acc.concat(curr), []);
|
|
822
|
+
}
|
|
823
|
+
ngOnInit() {
|
|
824
|
+
this.group = this.dynamicFormService.createFormGroup(this.formConfig);
|
|
825
|
+
this.ready.emit(this.group);
|
|
826
|
+
}
|
|
827
|
+
trackByFn(_index, field) {
|
|
828
|
+
return field.id;
|
|
829
|
+
}
|
|
830
|
+
/**
|
|
831
|
+
* Get the current value of the form.
|
|
832
|
+
* @param includeDisabledFields Include the disabled fields of the form, is enabled by default
|
|
833
|
+
*/
|
|
834
|
+
getFormValue(includeDisabledFields = true) {
|
|
835
|
+
const formValue = includeDisabledFields ? this.group.getRawValue() : this.group.value;
|
|
836
|
+
return formValue;
|
|
837
|
+
}
|
|
838
|
+
/**
|
|
839
|
+
* Provides an Observable to listen to changes of a specific field in the form.
|
|
840
|
+
*
|
|
841
|
+
* @param name Name of the field
|
|
842
|
+
* @returns Observable<any>
|
|
843
|
+
*/
|
|
844
|
+
onChange(name) {
|
|
845
|
+
const field = this.group.get(name);
|
|
846
|
+
if (!field) {
|
|
847
|
+
throw new Error(`Cannot find a field with the name ${name} in the FormGroup`);
|
|
848
|
+
}
|
|
849
|
+
return field.valueChanges;
|
|
850
|
+
}
|
|
851
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
852
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: DynamicFormComponent, isStandalone: true, selector: "dynamic-form", inputs: { formConfig: "formConfig" }, outputs: { ready: "ready" }, providers: [DynamicFormService], ngImport: i0, template: "<form [formGroup]=\"group\"\n class=\"dynamic-form\">\n <div *ngFor=\"let row of formConfig\"\n class=\"dynamic-form-row\">\n <dynamic-form-field *ngFor=\"let field of row; trackBy: trackByFn\"\n class=\"dynamic-form-field\"\n [id]=\"field.id\"\n [hidden]=\"field.hidden\"\n [ngClass]=\"[field.type, 'form-field-width-'+field.width]\"\n [group]=\"group\"\n [model]=\"field\">\n </dynamic-form-field>\n </div>\n</form>", styles: [".dynamic-form{width:100%}.dynamic-form .dynamic-form-row{width:100%;display:flex}.dynamic-form .dynamic-form-row .dynamic-form-field{width:100%;margin:4px 0}.dynamic-form .dynamic-form-row .dynamic-form-field:not(:last-of-type){margin-right:12px}.dynamic-form .dynamic-form-row .dynamic-form-field.button{flex:0}.dynamic-form .dynamic-form-row .form-field-width-1{width:1%}.dynamic-form .dynamic-form-row .form-field-width-2{width:2%}.dynamic-form .dynamic-form-row .form-field-width-3{width:3%}.dynamic-form .dynamic-form-row .form-field-width-4{width:4%}.dynamic-form .dynamic-form-row .form-field-width-5{width:5%}.dynamic-form .dynamic-form-row .form-field-width-6{width:6%}.dynamic-form .dynamic-form-row .form-field-width-7{width:7%}.dynamic-form .dynamic-form-row .form-field-width-8{width:8%}.dynamic-form .dynamic-form-row .form-field-width-9{width:9%}.dynamic-form .dynamic-form-row .form-field-width-10{width:10%}.dynamic-form .dynamic-form-row .form-field-width-11{width:11%}.dynamic-form .dynamic-form-row .form-field-width-12{width:12%}.dynamic-form .dynamic-form-row .form-field-width-13{width:13%}.dynamic-form .dynamic-form-row .form-field-width-14{width:14%}.dynamic-form .dynamic-form-row .form-field-width-15{width:15%}.dynamic-form .dynamic-form-row .form-field-width-16{width:16%}.dynamic-form .dynamic-form-row .form-field-width-17{width:17%}.dynamic-form .dynamic-form-row .form-field-width-18{width:18%}.dynamic-form .dynamic-form-row .form-field-width-19{width:19%}.dynamic-form .dynamic-form-row .form-field-width-20{width:20%}.dynamic-form .dynamic-form-row .form-field-width-21{width:21%}.dynamic-form .dynamic-form-row .form-field-width-22{width:22%}.dynamic-form .dynamic-form-row .form-field-width-23{width:23%}.dynamic-form .dynamic-form-row .form-field-width-24{width:24%}.dynamic-form .dynamic-form-row .form-field-width-25{width:25%}.dynamic-form .dynamic-form-row .form-field-width-26{width:26%}.dynamic-form .dynamic-form-row .form-field-width-27{width:27%}.dynamic-form .dynamic-form-row .form-field-width-28{width:28%}.dynamic-form .dynamic-form-row .form-field-width-29{width:29%}.dynamic-form .dynamic-form-row .form-field-width-30{width:30%}.dynamic-form .dynamic-form-row .form-field-width-31{width:31%}.dynamic-form .dynamic-form-row .form-field-width-32{width:32%}.dynamic-form .dynamic-form-row .form-field-width-33{width:33%}.dynamic-form .dynamic-form-row .form-field-width-34{width:34%}.dynamic-form .dynamic-form-row .form-field-width-35{width:35%}.dynamic-form .dynamic-form-row .form-field-width-36{width:36%}.dynamic-form .dynamic-form-row .form-field-width-37{width:37%}.dynamic-form .dynamic-form-row .form-field-width-38{width:38%}.dynamic-form .dynamic-form-row .form-field-width-39{width:39%}.dynamic-form .dynamic-form-row .form-field-width-40{width:40%}.dynamic-form .dynamic-form-row .form-field-width-41{width:41%}.dynamic-form .dynamic-form-row .form-field-width-42{width:42%}.dynamic-form .dynamic-form-row .form-field-width-43{width:43%}.dynamic-form .dynamic-form-row .form-field-width-44{width:44%}.dynamic-form .dynamic-form-row .form-field-width-45{width:45%}.dynamic-form .dynamic-form-row .form-field-width-46{width:46%}.dynamic-form .dynamic-form-row .form-field-width-47{width:47%}.dynamic-form .dynamic-form-row .form-field-width-48{width:48%}.dynamic-form .dynamic-form-row .form-field-width-49{width:49%}.dynamic-form .dynamic-form-row .form-field-width-50{width:50%}.dynamic-form .dynamic-form-row .form-field-width-51{width:51%}.dynamic-form .dynamic-form-row .form-field-width-52{width:52%}.dynamic-form .dynamic-form-row .form-field-width-53{width:53%}.dynamic-form .dynamic-form-row .form-field-width-54{width:54%}.dynamic-form .dynamic-form-row .form-field-width-55{width:55%}.dynamic-form .dynamic-form-row .form-field-width-56{width:56%}.dynamic-form .dynamic-form-row .form-field-width-57{width:57%}.dynamic-form .dynamic-form-row .form-field-width-58{width:58%}.dynamic-form .dynamic-form-row .form-field-width-59{width:59%}.dynamic-form .dynamic-form-row .form-field-width-60{width:60%}.dynamic-form .dynamic-form-row .form-field-width-61{width:61%}.dynamic-form .dynamic-form-row .form-field-width-62{width:62%}.dynamic-form .dynamic-form-row .form-field-width-63{width:63%}.dynamic-form .dynamic-form-row .form-field-width-64{width:64%}.dynamic-form .dynamic-form-row .form-field-width-65{width:65%}.dynamic-form .dynamic-form-row .form-field-width-66{width:66%}.dynamic-form .dynamic-form-row .form-field-width-67{width:67%}.dynamic-form .dynamic-form-row .form-field-width-68{width:68%}.dynamic-form .dynamic-form-row .form-field-width-69{width:69%}.dynamic-form .dynamic-form-row .form-field-width-70{width:70%}.dynamic-form .dynamic-form-row .form-field-width-71{width:71%}.dynamic-form .dynamic-form-row .form-field-width-72{width:72%}.dynamic-form .dynamic-form-row .form-field-width-73{width:73%}.dynamic-form .dynamic-form-row .form-field-width-74{width:74%}.dynamic-form .dynamic-form-row .form-field-width-75{width:75%}.dynamic-form .dynamic-form-row .form-field-width-76{width:76%}.dynamic-form .dynamic-form-row .form-field-width-77{width:77%}.dynamic-form .dynamic-form-row .form-field-width-78{width:78%}.dynamic-form .dynamic-form-row .form-field-width-79{width:79%}.dynamic-form .dynamic-form-row .form-field-width-80{width:80%}.dynamic-form .dynamic-form-row .form-field-width-81{width:81%}.dynamic-form .dynamic-form-row .form-field-width-82{width:82%}.dynamic-form .dynamic-form-row .form-field-width-83{width:83%}.dynamic-form .dynamic-form-row .form-field-width-84{width:84%}.dynamic-form .dynamic-form-row .form-field-width-85{width:85%}.dynamic-form .dynamic-form-row .form-field-width-86{width:86%}.dynamic-form .dynamic-form-row .form-field-width-87{width:87%}.dynamic-form .dynamic-form-row .form-field-width-88{width:88%}.dynamic-form .dynamic-form-row .form-field-width-89{width:89%}.dynamic-form .dynamic-form-row .form-field-width-90{width:90%}.dynamic-form .dynamic-form-row .form-field-width-91{width:91%}.dynamic-form .dynamic-form-row .form-field-width-92{width:92%}.dynamic-form .dynamic-form-row .form-field-width-93{width:93%}.dynamic-form .dynamic-form-row .form-field-width-94{width:94%}.dynamic-form .dynamic-form-row .form-field-width-95{width:95%}.dynamic-form .dynamic-form-row .form-field-width-96{width:96%}.dynamic-form .dynamic-form-row .form-field-width-97{width:97%}.dynamic-form .dynamic-form-row .form-field-width-98{width:98%}.dynamic-form .dynamic-form-row .form-field-width-99{width:99%}.dynamic-form .dynamic-form-row .form-field-width-100{width:100%}\n"], dependencies: [{ kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: DynamicFormFieldComponent, selector: "dynamic-form-field", inputs: ["model", "group"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
853
|
+
}
|
|
854
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: DynamicFormComponent, decorators: [{
|
|
855
|
+
type: Component,
|
|
856
|
+
args: [{ standalone: true, imports: [NgFor, NgClass, DynamicFormFieldComponent, ReactiveFormsModule], selector: 'dynamic-form', providers: [DynamicFormService], changeDetection: ChangeDetectionStrategy.OnPush, template: "<form [formGroup]=\"group\"\n class=\"dynamic-form\">\n <div *ngFor=\"let row of formConfig\"\n class=\"dynamic-form-row\">\n <dynamic-form-field *ngFor=\"let field of row; trackBy: trackByFn\"\n class=\"dynamic-form-field\"\n [id]=\"field.id\"\n [hidden]=\"field.hidden\"\n [ngClass]=\"[field.type, 'form-field-width-'+field.width]\"\n [group]=\"group\"\n [model]=\"field\">\n </dynamic-form-field>\n </div>\n</form>", styles: [".dynamic-form{width:100%}.dynamic-form .dynamic-form-row{width:100%;display:flex}.dynamic-form .dynamic-form-row .dynamic-form-field{width:100%;margin:4px 0}.dynamic-form .dynamic-form-row .dynamic-form-field:not(:last-of-type){margin-right:12px}.dynamic-form .dynamic-form-row .dynamic-form-field.button{flex:0}.dynamic-form .dynamic-form-row .form-field-width-1{width:1%}.dynamic-form .dynamic-form-row .form-field-width-2{width:2%}.dynamic-form .dynamic-form-row .form-field-width-3{width:3%}.dynamic-form .dynamic-form-row .form-field-width-4{width:4%}.dynamic-form .dynamic-form-row .form-field-width-5{width:5%}.dynamic-form .dynamic-form-row .form-field-width-6{width:6%}.dynamic-form .dynamic-form-row .form-field-width-7{width:7%}.dynamic-form .dynamic-form-row .form-field-width-8{width:8%}.dynamic-form .dynamic-form-row .form-field-width-9{width:9%}.dynamic-form .dynamic-form-row .form-field-width-10{width:10%}.dynamic-form .dynamic-form-row .form-field-width-11{width:11%}.dynamic-form .dynamic-form-row .form-field-width-12{width:12%}.dynamic-form .dynamic-form-row .form-field-width-13{width:13%}.dynamic-form .dynamic-form-row .form-field-width-14{width:14%}.dynamic-form .dynamic-form-row .form-field-width-15{width:15%}.dynamic-form .dynamic-form-row .form-field-width-16{width:16%}.dynamic-form .dynamic-form-row .form-field-width-17{width:17%}.dynamic-form .dynamic-form-row .form-field-width-18{width:18%}.dynamic-form .dynamic-form-row .form-field-width-19{width:19%}.dynamic-form .dynamic-form-row .form-field-width-20{width:20%}.dynamic-form .dynamic-form-row .form-field-width-21{width:21%}.dynamic-form .dynamic-form-row .form-field-width-22{width:22%}.dynamic-form .dynamic-form-row .form-field-width-23{width:23%}.dynamic-form .dynamic-form-row .form-field-width-24{width:24%}.dynamic-form .dynamic-form-row .form-field-width-25{width:25%}.dynamic-form .dynamic-form-row .form-field-width-26{width:26%}.dynamic-form .dynamic-form-row .form-field-width-27{width:27%}.dynamic-form .dynamic-form-row .form-field-width-28{width:28%}.dynamic-form .dynamic-form-row .form-field-width-29{width:29%}.dynamic-form .dynamic-form-row .form-field-width-30{width:30%}.dynamic-form .dynamic-form-row .form-field-width-31{width:31%}.dynamic-form .dynamic-form-row .form-field-width-32{width:32%}.dynamic-form .dynamic-form-row .form-field-width-33{width:33%}.dynamic-form .dynamic-form-row .form-field-width-34{width:34%}.dynamic-form .dynamic-form-row .form-field-width-35{width:35%}.dynamic-form .dynamic-form-row .form-field-width-36{width:36%}.dynamic-form .dynamic-form-row .form-field-width-37{width:37%}.dynamic-form .dynamic-form-row .form-field-width-38{width:38%}.dynamic-form .dynamic-form-row .form-field-width-39{width:39%}.dynamic-form .dynamic-form-row .form-field-width-40{width:40%}.dynamic-form .dynamic-form-row .form-field-width-41{width:41%}.dynamic-form .dynamic-form-row .form-field-width-42{width:42%}.dynamic-form .dynamic-form-row .form-field-width-43{width:43%}.dynamic-form .dynamic-form-row .form-field-width-44{width:44%}.dynamic-form .dynamic-form-row .form-field-width-45{width:45%}.dynamic-form .dynamic-form-row .form-field-width-46{width:46%}.dynamic-form .dynamic-form-row .form-field-width-47{width:47%}.dynamic-form .dynamic-form-row .form-field-width-48{width:48%}.dynamic-form .dynamic-form-row .form-field-width-49{width:49%}.dynamic-form .dynamic-form-row .form-field-width-50{width:50%}.dynamic-form .dynamic-form-row .form-field-width-51{width:51%}.dynamic-form .dynamic-form-row .form-field-width-52{width:52%}.dynamic-form .dynamic-form-row .form-field-width-53{width:53%}.dynamic-form .dynamic-form-row .form-field-width-54{width:54%}.dynamic-form .dynamic-form-row .form-field-width-55{width:55%}.dynamic-form .dynamic-form-row .form-field-width-56{width:56%}.dynamic-form .dynamic-form-row .form-field-width-57{width:57%}.dynamic-form .dynamic-form-row .form-field-width-58{width:58%}.dynamic-form .dynamic-form-row .form-field-width-59{width:59%}.dynamic-form .dynamic-form-row .form-field-width-60{width:60%}.dynamic-form .dynamic-form-row .form-field-width-61{width:61%}.dynamic-form .dynamic-form-row .form-field-width-62{width:62%}.dynamic-form .dynamic-form-row .form-field-width-63{width:63%}.dynamic-form .dynamic-form-row .form-field-width-64{width:64%}.dynamic-form .dynamic-form-row .form-field-width-65{width:65%}.dynamic-form .dynamic-form-row .form-field-width-66{width:66%}.dynamic-form .dynamic-form-row .form-field-width-67{width:67%}.dynamic-form .dynamic-form-row .form-field-width-68{width:68%}.dynamic-form .dynamic-form-row .form-field-width-69{width:69%}.dynamic-form .dynamic-form-row .form-field-width-70{width:70%}.dynamic-form .dynamic-form-row .form-field-width-71{width:71%}.dynamic-form .dynamic-form-row .form-field-width-72{width:72%}.dynamic-form .dynamic-form-row .form-field-width-73{width:73%}.dynamic-form .dynamic-form-row .form-field-width-74{width:74%}.dynamic-form .dynamic-form-row .form-field-width-75{width:75%}.dynamic-form .dynamic-form-row .form-field-width-76{width:76%}.dynamic-form .dynamic-form-row .form-field-width-77{width:77%}.dynamic-form .dynamic-form-row .form-field-width-78{width:78%}.dynamic-form .dynamic-form-row .form-field-width-79{width:79%}.dynamic-form .dynamic-form-row .form-field-width-80{width:80%}.dynamic-form .dynamic-form-row .form-field-width-81{width:81%}.dynamic-form .dynamic-form-row .form-field-width-82{width:82%}.dynamic-form .dynamic-form-row .form-field-width-83{width:83%}.dynamic-form .dynamic-form-row .form-field-width-84{width:84%}.dynamic-form .dynamic-form-row .form-field-width-85{width:85%}.dynamic-form .dynamic-form-row .form-field-width-86{width:86%}.dynamic-form .dynamic-form-row .form-field-width-87{width:87%}.dynamic-form .dynamic-form-row .form-field-width-88{width:88%}.dynamic-form .dynamic-form-row .form-field-width-89{width:89%}.dynamic-form .dynamic-form-row .form-field-width-90{width:90%}.dynamic-form .dynamic-form-row .form-field-width-91{width:91%}.dynamic-form .dynamic-form-row .form-field-width-92{width:92%}.dynamic-form .dynamic-form-row .form-field-width-93{width:93%}.dynamic-form .dynamic-form-row .form-field-width-94{width:94%}.dynamic-form .dynamic-form-row .form-field-width-95{width:95%}.dynamic-form .dynamic-form-row .form-field-width-96{width:96%}.dynamic-form .dynamic-form-row .form-field-width-97{width:97%}.dynamic-form .dynamic-form-row .form-field-width-98{width:98%}.dynamic-form .dynamic-form-row .form-field-width-99{width:99%}.dynamic-form .dynamic-form-row .form-field-width-100{width:100%}\n"] }]
|
|
857
|
+
}], propDecorators: { formConfig: [{
|
|
858
|
+
type: Input,
|
|
859
|
+
args: [{ required: true }]
|
|
860
|
+
}], ready: [{
|
|
861
|
+
type: Output
|
|
862
|
+
}] } });
|
|
863
|
+
|
|
864
|
+
/*
|
|
865
|
+
* Public API Surface of ngx-dynamic-form
|
|
866
|
+
*/
|
|
867
|
+
|
|
868
|
+
/**
|
|
869
|
+
* Generated bundle index. Do not edit.
|
|
870
|
+
*/
|
|
871
|
+
|
|
872
|
+
export { DYNAMIC_FORM_FIELD_BUTTON, DYNAMIC_FORM_FIELD_CHECKBOX, DYNAMIC_FORM_FIELD_INPUT, DYNAMIC_FORM_FIELD_MAP_FN, DYNAMIC_FORM_FIELD_READONLY, DYNAMIC_FORM_FIELD_SELECT, DYNAMIC_FORM_FIELD_TEXTAREA, DynamicButton, DynamicCheckbox, DynamicFormComponent, DynamicFormFieldBaseComponent, DynamicFormFieldModel, DynamicFormFieldOptionModel, DynamicFormFieldValueModel, DynamicFormService, DynamicFormValidators, DynamicInput, DynamicReadonly, DynamicSelect, DynamicTextarea, RELATION_ACTIONS, RelationActionType, RelationOperator };
|
|
873
|
+
//# sourceMappingURL=olafvv-ngx-dynamic-form.mjs.map
|