@dynamic-field-kit/angular 1.2.10 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/README.md +113 -4
- package/dist/README.md +113 -4
- package/dist/components/BaseInput.d.ts +23 -11
- package/dist/components/DynamicInput.d.ts +19 -8
- package/dist/components/FieldInput.d.ts +15 -7
- package/dist/components/MultiFieldInput.d.ts +30 -4
- package/dist/esm2022/components/BaseInput.mjs +17 -18
- package/dist/esm2022/components/DynamicInput.mjs +166 -84
- package/dist/esm2022/components/FieldInput.mjs +54 -26
- package/dist/esm2022/components/MultiFieldInput.mjs +282 -29
- package/dist/esm2022/fieldRegistryToken.mjs +12 -0
- package/dist/esm2022/layout/defaultLayouts.mjs +70 -23
- package/dist/esm2022/layout/index.mjs +2 -1
- package/dist/esm2022/layout/layoutRegistry.mjs +14 -0
- package/dist/esm2022/public-api.mjs +6 -2
- package/dist/esm2022/types/layout.mjs +1 -1
- package/dist/fesm2022/dynamic-field-kit-angular.mjs +604 -173
- package/dist/fesm2022/dynamic-field-kit-angular.mjs.map +1 -1
- package/dist/fieldRegistryToken.d.ts +3 -0
- package/dist/layout/defaultLayouts.d.ts +21 -3
- package/dist/layout/index.d.ts +1 -0
- package/dist/layout/layoutRegistry.d.ts +12 -0
- package/dist/public-api.d.ts +5 -2
- package/dist/types/layout.d.ts +4 -1
- package/package.json +19 -8
- package/src/components/BaseInput.ts +36 -10
- package/src/components/DynamicInput.ts +196 -104
- package/src/components/FieldInput.ts +43 -18
- package/src/components/MultiFieldInput.ts +275 -19
- package/src/fieldRegistryToken.ts +15 -0
- package/src/layout/defaultLayouts.ts +42 -10
- package/src/layout/index.ts +1 -0
- package/src/layout/layoutRegistry.ts +25 -0
- package/src/public-api.ts +40 -24
- package/src/types/layout.ts +14 -1
- package/test/DynamicInput.spec.ts +230 -0
- package/test/FieldInput.spec.ts +146 -0
- package/test/MultiFieldInput.spec.ts +256 -0
- package/test/helpers/renderers.ts +89 -0
- package/test/layout.spec.ts +119 -0
- package/test/publicApi.spec.ts +64 -0
- package/test/setup.ts +12 -0
- package/test/smoke.spec.ts +27 -0
- package/tsconfig.json +13 -13
- package/tsconfig.spec.json +9 -0
- package/vitest.config.ts +30 -0
- package/src/adapters/tailwind.ts +0 -13
- package/src/components/imports.ts +0 -3
- package/src/examples/index.ts +0 -4
- package/src/examples/registerExample.ts +0 -7
- package/src/examples/text-field.component.ts +0 -18
- package/src/types.ts +0 -1
|
@@ -1,27 +1,45 @@
|
|
|
1
1
|
import { CommonModule } from '@angular/common';
|
|
2
2
|
import {
|
|
3
|
+
AfterViewInit,
|
|
4
|
+
ChangeDetectionStrategy,
|
|
3
5
|
Component,
|
|
4
6
|
ComponentRef,
|
|
5
|
-
Input,
|
|
6
|
-
Output,
|
|
7
7
|
EventEmitter,
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
inject,
|
|
9
|
+
Input,
|
|
10
10
|
OnChanges,
|
|
11
|
-
AfterViewInit,
|
|
12
11
|
OnDestroy,
|
|
12
|
+
Output,
|
|
13
13
|
SimpleChanges,
|
|
14
14
|
Type,
|
|
15
|
-
|
|
15
|
+
ViewChild,
|
|
16
|
+
ViewContainerRef,
|
|
16
17
|
} from '@angular/core';
|
|
17
|
-
import {
|
|
18
|
+
import { FieldTypeKey, Properties } from '@dynamic-field-kit/core';
|
|
18
19
|
import { Subscription } from 'rxjs';
|
|
20
|
+
import { FIELD_REGISTRY } from '../fieldRegistryToken';
|
|
19
21
|
import { BaseInputComponent } from './BaseInput';
|
|
20
22
|
|
|
23
|
+
// Only the framework-agnostic FieldRendererProps keys. Domain-specific props
|
|
24
|
+
// reach the renderer through `extraProps` (FieldDescription.props) instead.
|
|
25
|
+
const KNOWN_PROPS = [
|
|
26
|
+
'value',
|
|
27
|
+
'label',
|
|
28
|
+
'placeholder',
|
|
29
|
+
'required',
|
|
30
|
+
'disabled',
|
|
31
|
+
'readOnly',
|
|
32
|
+
'error',
|
|
33
|
+
'options',
|
|
34
|
+
'className',
|
|
35
|
+
'description',
|
|
36
|
+
] as const;
|
|
37
|
+
|
|
21
38
|
@Component({
|
|
22
39
|
selector: 'dfk-dynamic-input',
|
|
23
40
|
standalone: true,
|
|
24
41
|
imports: [CommonModule],
|
|
42
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
25
43
|
template: `<div #host style="display: contents;"></div>`,
|
|
26
44
|
})
|
|
27
45
|
export class DynamicInput
|
|
@@ -29,160 +47,234 @@ export class DynamicInput
|
|
|
29
47
|
implements OnChanges, AfterViewInit, OnDestroy
|
|
30
48
|
{
|
|
31
49
|
@Input() type!: FieldTypeKey;
|
|
32
|
-
|
|
33
|
-
@
|
|
50
|
+
// Extra, framework-agnostic props forwarded verbatim to the renderer.
|
|
51
|
+
@Input() extraProps?: Properties;
|
|
52
|
+
@Output() override valueChange = new EventEmitter<unknown>();
|
|
53
|
+
@Output() onChange = new EventEmitter<unknown>();
|
|
54
|
+
|
|
55
|
+
private registry = inject(FIELD_REGISTRY);
|
|
34
56
|
|
|
35
57
|
@ViewChild('host', { read: ViewContainerRef, static: false })
|
|
36
58
|
host!: ViewContainerRef;
|
|
37
|
-
private compRef?: ComponentRef<
|
|
38
|
-
private inputInstance?:
|
|
59
|
+
private compRef?: ComponentRef<unknown>;
|
|
60
|
+
private inputInstance?: unknown;
|
|
39
61
|
private subscriptions: Subscription[] = [];
|
|
62
|
+
// Tracks which KNOWN_PROPS were actually supplied to DynamicInput (via
|
|
63
|
+
// SimpleChanges), independent of TS class-field emit. See applyProps.
|
|
64
|
+
private supplied = new Set<string>();
|
|
40
65
|
|
|
41
|
-
ngOnChanges(changes: SimpleChanges) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
66
|
+
ngOnChanges(changes: SimpleChanges): void {
|
|
67
|
+
super.ngOnChanges(changes);
|
|
68
|
+
|
|
69
|
+
for (const prop of KNOWN_PROPS) {
|
|
70
|
+
if (changes[prop]) {
|
|
71
|
+
this.supplied.add(prop);
|
|
72
|
+
}
|
|
45
73
|
}
|
|
46
74
|
|
|
47
75
|
if (this.inputInstance) {
|
|
48
|
-
this.
|
|
49
|
-
|
|
50
|
-
const childChanges: SimpleChanges = {};
|
|
51
|
-
for (const prop in changes) {
|
|
52
|
-
childChanges[prop] = new SimpleChange(
|
|
53
|
-
changes[prop].previousValue,
|
|
54
|
-
changes[prop].currentValue,
|
|
55
|
-
changes[prop].firstChange
|
|
56
|
-
);
|
|
57
|
-
}
|
|
76
|
+
this.syncPropsToInstance(changes);
|
|
77
|
+
}
|
|
58
78
|
|
|
59
|
-
|
|
60
|
-
this.
|
|
61
|
-
} else if (this.host) {
|
|
79
|
+
if (changes['type'] && !changes['type'].firstChange && this.host) {
|
|
80
|
+
this.render();
|
|
81
|
+
} else if (!this.inputInstance && this.host) {
|
|
62
82
|
this.render();
|
|
63
83
|
}
|
|
64
84
|
}
|
|
65
85
|
|
|
66
|
-
ngAfterViewInit() {
|
|
86
|
+
ngAfterViewInit(): void {
|
|
67
87
|
this.render();
|
|
68
88
|
}
|
|
69
89
|
|
|
70
|
-
ngOnDestroy() {
|
|
90
|
+
ngOnDestroy(): void {
|
|
91
|
+
this.cleanup();
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
private syncPropsToInstance(changes: SimpleChanges): void {
|
|
95
|
+
if (!this.inputInstance) {
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
for (const prop of KNOWN_PROPS) {
|
|
100
|
+
if (changes[prop] && this.inputInstance) {
|
|
101
|
+
(this.inputInstance as Record<string, unknown>)[prop] = (
|
|
102
|
+
this as Record<string, unknown>
|
|
103
|
+
)[prop];
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
if (changes['extraProps']) {
|
|
107
|
+
this.applyExtraProps(this.inputInstance);
|
|
108
|
+
}
|
|
109
|
+
this.compRef?.changeDetectorRef?.detectChanges();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
private cleanup(): void {
|
|
71
113
|
this.cleanupSubscriptions();
|
|
72
114
|
this.cleanupRenderedComponent();
|
|
73
115
|
}
|
|
74
116
|
|
|
75
|
-
private cleanupSubscriptions() {
|
|
117
|
+
private cleanupSubscriptions(): void {
|
|
76
118
|
this.subscriptions.forEach((s) => s.unsubscribe());
|
|
77
119
|
this.subscriptions = [];
|
|
78
120
|
}
|
|
79
121
|
|
|
80
|
-
private
|
|
81
|
-
|
|
82
|
-
this.
|
|
83
|
-
this.
|
|
122
|
+
private cleanupRenderedComponent(): void {
|
|
123
|
+
this.compRef?.destroy();
|
|
124
|
+
this.compRef = undefined;
|
|
125
|
+
this.inputInstance = undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
private render(): void {
|
|
129
|
+
const Renderer = this.registry.get(this.type);
|
|
130
|
+
this.cleanup();
|
|
84
131
|
this.host.clear();
|
|
132
|
+
|
|
85
133
|
if (!Renderer) {
|
|
86
|
-
|
|
87
|
-
el.textContent = `Unknown field type: ${this.type}`;
|
|
88
|
-
this.host.element.nativeElement.appendChild(el);
|
|
134
|
+
this.renderError(`Unknown field type: ${this.type}`);
|
|
89
135
|
return;
|
|
90
136
|
}
|
|
91
137
|
|
|
138
|
+
if (this.isComponentType(Renderer)) {
|
|
139
|
+
this.renderComponent(Renderer as unknown as Type<unknown>);
|
|
140
|
+
} else if (typeof Renderer === 'function') {
|
|
141
|
+
this.renderFallback(Renderer);
|
|
142
|
+
} else {
|
|
143
|
+
this.renderError(`Invalid renderer for type: ${this.type}`);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Angular component classes carry a static ɵcmp. Checked instead of
|
|
148
|
+
// reflectComponentType() because the peer range starts at Angular 13 and
|
|
149
|
+
// reflectComponentType is v14+. Plain function renderers have no ɵcmp and
|
|
150
|
+
// fall through to renderFallback. Uses hasOwnProperty (not `in`) so a
|
|
151
|
+
// class that merely extends a component without its own @Component
|
|
152
|
+
// decorator - and would otherwise inherit the parent's static ɵcmp via the
|
|
153
|
+
// prototype chain - is not mistaken for a component in its own right.
|
|
154
|
+
private isComponentType(renderer: unknown): boolean {
|
|
155
|
+
return (
|
|
156
|
+
typeof renderer === 'function' &&
|
|
157
|
+
Object.prototype.hasOwnProperty.call(renderer, 'ɵcmp')
|
|
158
|
+
);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
private renderComponent(compType: Type<unknown>): void {
|
|
92
162
|
try {
|
|
93
|
-
const compType = Renderer as unknown as Type<any>;
|
|
94
163
|
const compRef = this.host.createComponent(compType);
|
|
95
164
|
const instance = compRef.instance;
|
|
165
|
+
|
|
96
166
|
if (!instance) {
|
|
97
|
-
|
|
167
|
+
this.renderError(`Failed to create instance for ${this.type}`);
|
|
168
|
+
return;
|
|
98
169
|
}
|
|
99
170
|
|
|
100
|
-
this.
|
|
171
|
+
this.applyProps(instance);
|
|
172
|
+
this.bindOutputs(instance);
|
|
101
173
|
|
|
102
|
-
const subA = this.bindOutput(instance, 'valueChange');
|
|
103
|
-
if (subA) {
|
|
104
|
-
this.subscriptions.push(subA);
|
|
105
|
-
}
|
|
106
|
-
const subB = this.bindOutput(instance, 'onValueChange');
|
|
107
|
-
if (subB) {
|
|
108
|
-
this.subscriptions.push(subB);
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
instance.changeDetectorRef?.detectChanges();
|
|
112
174
|
this.compRef = compRef;
|
|
113
175
|
this.inputInstance = instance;
|
|
114
176
|
compRef.changeDetectorRef.detectChanges();
|
|
115
|
-
} catch
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
description: this.description,
|
|
127
|
-
disabled: this.disabled,
|
|
128
|
-
errorMessage: this.errorMessage,
|
|
129
|
-
};
|
|
130
|
-
const out = (Renderer as (props: unknown) => unknown)(props);
|
|
131
|
-
if (typeof out === 'string') {
|
|
132
|
-
const el = document.createElement('div');
|
|
133
|
-
el.innerHTML = out;
|
|
134
|
-
this.host.element.nativeElement.appendChild(el);
|
|
135
|
-
}
|
|
136
|
-
} catch (e) {
|
|
177
|
+
} catch {
|
|
178
|
+
this.renderError(`Failed to render field: ${this.type}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private renderFallback(renderer: unknown): void {
|
|
183
|
+
try {
|
|
184
|
+
const props = this.getFallbackProps();
|
|
185
|
+
const result = (renderer as (props: unknown) => string)(props);
|
|
186
|
+
|
|
187
|
+
if (typeof result === 'string') {
|
|
137
188
|
const el = document.createElement('div');
|
|
138
|
-
el.
|
|
189
|
+
el.innerHTML = result;
|
|
139
190
|
this.host.element.nativeElement.appendChild(el);
|
|
140
191
|
}
|
|
192
|
+
} catch {
|
|
193
|
+
this.renderError(`Failed to render field: ${this.type}`);
|
|
141
194
|
}
|
|
142
195
|
}
|
|
143
196
|
|
|
144
|
-
private
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
'
|
|
150
|
-
'
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
197
|
+
private getFallbackProps(): Record<string, unknown> {
|
|
198
|
+
return {
|
|
199
|
+
...this.extraProps,
|
|
200
|
+
value: this.value,
|
|
201
|
+
onValueChange: (v: unknown) => this.emitValue(v),
|
|
202
|
+
label: this.label ?? '',
|
|
203
|
+
placeholder: this.placeholder ?? '',
|
|
204
|
+
required: this.required ?? false,
|
|
205
|
+
disabled: this.disabled ?? false,
|
|
206
|
+
readOnly: this.readOnly ?? false,
|
|
207
|
+
error: this.error,
|
|
208
|
+
options: this.options ?? [],
|
|
209
|
+
className: this.className ?? '',
|
|
210
|
+
description: this.description ?? '',
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
// Gates on `this.supplied` (populated from SimpleChanges in ngOnChanges),
|
|
215
|
+
// not on `prop in instanceObj` or `prop in this`. Both `in` checks test a
|
|
216
|
+
// TypeScript class-field emit artifact rather than intent: whether a
|
|
217
|
+
// property slot exists at runtime depends on the compile target
|
|
218
|
+
// (useDefineForClassFields is false below ES2022, true at ES2022+), so the
|
|
219
|
+
// same source can behave oppositely between this package's test build and
|
|
220
|
+
// its shipped ES2022 bundle, where every declared field is always an own
|
|
221
|
+
// property. `this.supplied` instead reflects only whether Angular ever
|
|
222
|
+
// fired a SimpleChange for that input, i.e. whether the prop was *bound*
|
|
223
|
+
// at all - it skips only props DynamicInput was never given a binding
|
|
224
|
+
// for. It is NOT a general "renderer defaults survive" guarantee: Angular
|
|
225
|
+
// fires a firstChange SimpleChange for every bound input even when the
|
|
226
|
+
// bound value is undefined, and FieldInput's template binds all
|
|
227
|
+
// KNOWN_PROPS unconditionally, so on the real
|
|
228
|
+
// MultiFieldInput -> FieldInput -> DynamicInput path every prop counts as
|
|
229
|
+
// supplied and renderer-side defaults (e.g. `@Input() label = 'None'`)
|
|
230
|
+
// are still overwritten with undefined. This only helps when DynamicInput
|
|
231
|
+
// is mounted directly with some inputs left unbound.
|
|
232
|
+
private applyProps(instance: unknown): void {
|
|
233
|
+
const instanceObj = instance as Record<string, unknown>;
|
|
234
|
+
for (const prop of KNOWN_PROPS) {
|
|
235
|
+
if (this.supplied.has(prop)) {
|
|
236
|
+
instanceObj[prop] = (this as Record<string, unknown>)[prop];
|
|
159
237
|
}
|
|
160
238
|
}
|
|
239
|
+
this.applyExtraProps(instance);
|
|
161
240
|
}
|
|
162
241
|
|
|
163
|
-
private
|
|
164
|
-
instance
|
|
165
|
-
outputName: 'valueChange' | 'onValueChange'
|
|
166
|
-
): Subscription | undefined {
|
|
167
|
-
const output = instance?.[outputName];
|
|
168
|
-
if (!output || typeof output.subscribe !== 'function') {
|
|
242
|
+
private applyExtraProps(instance: unknown): void {
|
|
243
|
+
if (!instance || !this.extraProps) {
|
|
169
244
|
return;
|
|
170
245
|
}
|
|
246
|
+
const instanceObj = instance as Record<string, unknown>;
|
|
247
|
+
for (const [key, value] of Object.entries(this.extraProps)) {
|
|
248
|
+
instanceObj[key] = value;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
private bindOutputs(instance: unknown): void {
|
|
253
|
+
const outputNames: Array<'valueChange' | 'onValueChange'> = [
|
|
254
|
+
'valueChange',
|
|
255
|
+
'onValueChange',
|
|
256
|
+
];
|
|
171
257
|
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
258
|
+
for (const outputName of outputNames) {
|
|
259
|
+
const output = (instance as Record<string, unknown>)[outputName];
|
|
260
|
+
if (output && typeof output === 'object' && 'subscribe' in output) {
|
|
261
|
+
const sub = (
|
|
262
|
+
output as { subscribe: (cb: (v: unknown) => void) => Subscription }
|
|
263
|
+
).subscribe((value: unknown) => this.emitValue(value));
|
|
264
|
+
this.subscriptions.push(sub);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
176
267
|
}
|
|
177
268
|
|
|
178
|
-
private emitValue(value:
|
|
269
|
+
private emitValue(value: unknown): void {
|
|
179
270
|
this.valueChange.emit(value);
|
|
180
271
|
this.onChange.emit(value);
|
|
181
272
|
}
|
|
182
273
|
|
|
183
|
-
private
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
274
|
+
private renderError(message: string): void {
|
|
275
|
+
const el = document.createElement('div');
|
|
276
|
+
el.textContent = message;
|
|
277
|
+
el.style.color = 'red';
|
|
278
|
+
this.host.element.nativeElement.appendChild(el);
|
|
187
279
|
}
|
|
188
280
|
}
|
|
@@ -1,49 +1,74 @@
|
|
|
1
1
|
import { NgIf } from '@angular/common';
|
|
2
|
-
import {
|
|
3
|
-
|
|
2
|
+
import {
|
|
3
|
+
ChangeDetectionStrategy,
|
|
4
|
+
ChangeDetectorRef,
|
|
5
|
+
Component,
|
|
6
|
+
EventEmitter,
|
|
7
|
+
Input,
|
|
8
|
+
OnChanges,
|
|
9
|
+
Output,
|
|
10
|
+
SimpleChanges,
|
|
11
|
+
} from '@angular/core';
|
|
12
|
+
import { FieldDescription } from '@dynamic-field-kit/core';
|
|
4
13
|
import { DynamicInput } from './DynamicInput';
|
|
5
14
|
|
|
6
15
|
@Component({
|
|
7
16
|
selector: 'dfk-field-input',
|
|
8
17
|
standalone: true,
|
|
9
18
|
imports: [NgIf, DynamicInput],
|
|
19
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
10
20
|
template: `
|
|
11
21
|
<dfk-dynamic-input
|
|
12
|
-
*ngIf="
|
|
22
|
+
*ngIf="shouldRender"
|
|
13
23
|
[type]="fieldDescription!.type"
|
|
14
|
-
[value]="
|
|
24
|
+
[value]="value"
|
|
15
25
|
[label]="fieldDescription!.label"
|
|
16
26
|
[placeholder]="fieldDescription!.placeholder"
|
|
17
27
|
[required]="fieldDescription!.required"
|
|
18
|
-
[description]="fieldDescription!.description"
|
|
19
|
-
[options]="
|
|
28
|
+
[description]="$any(fieldDescription!.description)"
|
|
29
|
+
[options]="resolvedOptions"
|
|
20
30
|
[className]="fieldDescription!.className"
|
|
21
31
|
(valueChange)="
|
|
22
32
|
onValueChangeField.emit({ value: $event, key: fieldDescription!.name })
|
|
23
33
|
"
|
|
24
|
-
[disabled]="
|
|
25
|
-
[
|
|
34
|
+
[disabled]="disabled"
|
|
35
|
+
[readOnly]="readOnly"
|
|
36
|
+
[error]="$any(error)"
|
|
37
|
+
[extraProps]="fieldDescription!.props"
|
|
26
38
|
></dfk-dynamic-input>
|
|
27
39
|
`,
|
|
28
40
|
})
|
|
29
|
-
export class FieldInput {
|
|
41
|
+
export class FieldInput implements OnChanges {
|
|
30
42
|
@Input() fieldDescription?: FieldDescription;
|
|
31
|
-
@Input()
|
|
43
|
+
@Input() value?: unknown;
|
|
44
|
+
@Input() options?: Record<string, unknown>[];
|
|
45
|
+
@Input() disabled?: boolean;
|
|
46
|
+
@Input() readOnly?: boolean;
|
|
47
|
+
@Input() error?: string | string[];
|
|
32
48
|
@Output() onValueChangeField = new EventEmitter<{
|
|
33
|
-
value:
|
|
49
|
+
value: unknown;
|
|
34
50
|
key: string;
|
|
35
51
|
}>();
|
|
36
52
|
|
|
37
|
-
|
|
38
|
-
|
|
53
|
+
shouldRender = false;
|
|
54
|
+
|
|
55
|
+
get resolvedOptions(): Record<string, unknown>[] | undefined {
|
|
56
|
+
if (this.options) {
|
|
57
|
+
return this.options;
|
|
58
|
+
}
|
|
59
|
+
if (!this.fieldDescription?.options) {
|
|
39
60
|
return undefined;
|
|
40
61
|
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
if (value === undefined && this.fieldDescription.type === 'text') {
|
|
44
|
-
return '';
|
|
62
|
+
if (typeof this.fieldDescription.options === 'function') {
|
|
63
|
+
return undefined;
|
|
45
64
|
}
|
|
65
|
+
return this.fieldDescription.options;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
constructor(private cdr: ChangeDetectorRef) {}
|
|
46
69
|
|
|
47
|
-
|
|
70
|
+
ngOnChanges(_changes: SimpleChanges): void {
|
|
71
|
+
this.shouldRender = !!this.fieldDescription;
|
|
72
|
+
this.cdr.markForCheck();
|
|
48
73
|
}
|
|
49
74
|
}
|