@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.
Files changed (70) hide show
  1. package/README.md +55 -0
  2. package/esm2022/lib/components/dynamic-form/dynamic-form.component.mjs +59 -0
  3. package/esm2022/lib/components/dynamic-form-field/dynamic-form-field.component.mjs +129 -0
  4. package/esm2022/lib/controls/button/dynamic-button.component.mjs +22 -0
  5. package/esm2022/lib/controls/button/dynamic-button.model.mjs +12 -0
  6. package/esm2022/lib/controls/checkbox/dynamic-checkbox.component.mjs +32 -0
  7. package/esm2022/lib/controls/checkbox/dynamic-checkbox.model.mjs +21 -0
  8. package/esm2022/lib/controls/index.mjs +7 -0
  9. package/esm2022/lib/controls/input/dynamic-input.component.mjs +51 -0
  10. package/esm2022/lib/controls/input/dynamic-input.model.mjs +18 -0
  11. package/esm2022/lib/controls/readonly/dynamic-readonly.component.mjs +18 -0
  12. package/esm2022/lib/controls/readonly/dynamic-readonly.model.mjs +9 -0
  13. package/esm2022/lib/controls/select/dynamic-select.component.mjs +42 -0
  14. package/esm2022/lib/controls/select/dynamic-select.model.mjs +11 -0
  15. package/esm2022/lib/controls/textarea/dynamic-textarea.component.mjs +45 -0
  16. package/esm2022/lib/controls/textarea/dynamic-textarea.model.mjs +15 -0
  17. package/esm2022/lib/models/classes/dynamic-form-field-base-component.mjs +34 -0
  18. package/esm2022/lib/models/classes/dynamic-form-field-model.mjs +24 -0
  19. package/esm2022/lib/models/classes/dynamic-form-field-option-model.mjs +48 -0
  20. package/esm2022/lib/models/classes/dynamic-form-field-value-model.mjs +24 -0
  21. package/esm2022/lib/models/classes/dynamic-form-validators.mjs +73 -0
  22. package/esm2022/lib/models/constants/dynamic-relations.const.mjs +47 -0
  23. package/esm2022/lib/models/index.mjs +11 -0
  24. package/esm2022/lib/models/interfaces/dynamic-form-field-config.interface.mjs +2 -0
  25. package/esm2022/lib/models/interfaces/dynamic-form-validator.interface.mjs +2 -0
  26. package/esm2022/lib/models/tokens/dynamic-form-field-map-fn.token.mjs +3 -0
  27. package/esm2022/lib/models/types/dynamic-form-config.type.mjs +2 -0
  28. package/esm2022/lib/models/types/dynamic-form-hook.type.mjs +2 -0
  29. package/esm2022/lib/models/types/related-form-controls.type.mjs +2 -0
  30. package/esm2022/lib/services/dynamic-form-relations.service.mjs +103 -0
  31. package/esm2022/lib/services/dynamic-form.service.mjs +77 -0
  32. package/esm2022/lib/services/dynamic-validations.service.mjs +37 -0
  33. package/esm2022/olafvv-ngx-dynamic-form.mjs +5 -0
  34. package/esm2022/public-api.mjs +8 -0
  35. package/fesm2022/olafvv-ngx-dynamic-form.mjs +873 -0
  36. package/fesm2022/olafvv-ngx-dynamic-form.mjs.map +1 -0
  37. package/index.d.ts +5 -0
  38. package/lib/components/dynamic-form/dynamic-form.component.d.ts +32 -0
  39. package/lib/components/dynamic-form-field/dynamic-form-field.component.d.ts +44 -0
  40. package/lib/controls/button/dynamic-button.component.d.ts +11 -0
  41. package/lib/controls/button/dynamic-button.model.d.ts +15 -0
  42. package/lib/controls/checkbox/dynamic-checkbox.component.d.ts +15 -0
  43. package/lib/controls/checkbox/dynamic-checkbox.model.d.ts +15 -0
  44. package/lib/controls/index.d.ts +6 -0
  45. package/lib/controls/input/dynamic-input.component.d.ts +19 -0
  46. package/lib/controls/input/dynamic-input.model.d.ts +27 -0
  47. package/lib/controls/readonly/dynamic-readonly.component.d.ts +10 -0
  48. package/lib/controls/readonly/dynamic-readonly.model.d.ts +9 -0
  49. package/lib/controls/select/dynamic-select.component.d.ts +16 -0
  50. package/lib/controls/select/dynamic-select.model.d.ts +12 -0
  51. package/lib/controls/textarea/dynamic-textarea.component.d.ts +18 -0
  52. package/lib/controls/textarea/dynamic-textarea.model.d.ts +21 -0
  53. package/lib/models/classes/dynamic-form-field-base-component.d.ts +26 -0
  54. package/lib/models/classes/dynamic-form-field-model.d.ts +22 -0
  55. package/lib/models/classes/dynamic-form-field-option-model.d.ts +41 -0
  56. package/lib/models/classes/dynamic-form-field-value-model.d.ts +18 -0
  57. package/lib/models/classes/dynamic-form-validators.d.ts +48 -0
  58. package/lib/models/constants/dynamic-relations.const.d.ts +30 -0
  59. package/lib/models/index.d.ts +10 -0
  60. package/lib/models/interfaces/dynamic-form-field-config.interface.d.ts +60 -0
  61. package/lib/models/interfaces/dynamic-form-validator.interface.d.ts +6 -0
  62. package/lib/models/tokens/dynamic-form-field-map-fn.token.d.ts +2 -0
  63. package/lib/models/types/dynamic-form-config.type.d.ts +2 -0
  64. package/lib/models/types/dynamic-form-hook.type.d.ts +1 -0
  65. package/lib/models/types/related-form-controls.type.d.ts +4 -0
  66. package/lib/services/dynamic-form-relations.service.d.ts +26 -0
  67. package/lib/services/dynamic-form.service.d.ts +42 -0
  68. package/lib/services/dynamic-validations.service.d.ts +20 -0
  69. package/package.json +28 -0
  70. 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