@ng-modular-forms/core 0.4.0 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +5 -15
- package/fesm2022/ng-modular-forms-core.mjs +183 -154
- package/fesm2022/ng-modular-forms-core.mjs.map +1 -1
- package/lib/base/form-control-base.d.ts +34 -0
- package/lib/{form-handler-base.d.ts → base/form-handler-base.d.ts} +3 -3
- package/lib/base/form-mapper-base.d.ts +4 -0
- package/lib/form-hydrator.d.ts +8 -0
- package/lib/form-orchestrator.d.ts +41 -0
- package/lib/form-serializer.d.ts +8 -0
- package/lib/{form.util.d.ts → form-util.d.ts} +0 -1
- package/lib/types.d.ts +11 -0
- package/package.json +1 -1
- package/public-api.d.ts +8 -5
- package/lib/form-control-base.d.ts +0 -37
- package/lib/form-mapper-base.d.ts +0 -13
- package/lib/form-orchestrator-base.d.ts +0 -50
package/README.md
CHANGED
|
@@ -23,26 +23,16 @@ Coordinates form structure and lifecycle.
|
|
|
23
23
|
```ts
|
|
24
24
|
@Component({...})
|
|
25
25
|
export class ExampleComponent extends FormOrchestratorBase {
|
|
26
|
-
form = new FormGroup({});
|
|
27
26
|
|
|
28
27
|
ngOnInit() {
|
|
29
28
|
// Handlers are not required if there is no reactive logic or value change subscriptions.
|
|
30
29
|
const mainHandler = inject(ExampleFormHandler);
|
|
31
30
|
const sectionAHandler = inject(SectionAHandler);
|
|
32
31
|
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
subHandlers: {
|
|
36
|
-
sectionA: sectionAHandler
|
|
37
|
-
}
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
this.initialize(this.form, formOptions);
|
|
41
|
-
}
|
|
32
|
+
form = new FormGroup({});
|
|
33
|
+
handlers = [mainHandler, sectionAHandler]
|
|
42
34
|
|
|
43
|
-
|
|
44
|
-
onSubformReady(form: FormGroup, key: string) {
|
|
45
|
-
super.onSubformReady(form, key);
|
|
35
|
+
this.initialize(form, handlers);
|
|
46
36
|
}
|
|
47
37
|
}
|
|
48
38
|
```
|
|
@@ -60,8 +50,8 @@ type ControlNames = (typeof CONTROL_NAMES)[number];
|
|
|
60
50
|
|
|
61
51
|
@Injectable()
|
|
62
52
|
export class SectionAHandler extends FormHandlerBase<ControlNames> {
|
|
63
|
-
override getReactiveLogic(): Subscription {
|
|
64
|
-
this.registerControls(
|
|
53
|
+
override getReactiveLogic(form?: FormGroup): Subscription {
|
|
54
|
+
this.registerControls(form, [...CONTROL_NAMES]);
|
|
65
55
|
|
|
66
56
|
return this.valueChangesOf("fieldA").subscribe((value) => {
|
|
67
57
|
if (value) {
|
|
@@ -1,85 +1,101 @@
|
|
|
1
|
-
import { NgControl, Validators, FormGroup } from '@angular/forms';
|
|
1
|
+
import { NgControl, FormControl, Validators, TouchedChangeEvent, FormGroup } from '@angular/forms';
|
|
2
2
|
import * as i0 from '@angular/core';
|
|
3
|
-
import { inject, ChangeDetectorRef, DestroyRef, input, booleanAttribute, signal, computed,
|
|
3
|
+
import { inject, ChangeDetectorRef, DestroyRef, input, booleanAttribute, signal, computed, effect, Directive, Injectable } from '@angular/core';
|
|
4
4
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
5
|
-
import { Subscription } from 'rxjs';
|
|
5
|
+
import { Subscription, startWith } from 'rxjs';
|
|
6
6
|
|
|
7
7
|
class FormControlBase {
|
|
8
|
-
static nextId = 0;
|
|
9
|
-
id = `nmf-form-control-${FormControlBase.nextId++}`;
|
|
10
8
|
cdr = inject(ChangeDetectorRef);
|
|
11
9
|
destroyRef = inject(DestroyRef);
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
});
|
|
10
|
+
static nextId = 0;
|
|
11
|
+
id = input(`nmf-form-control-${FormControlBase.nextId++}`);
|
|
12
|
+
_id = input(null, { alias: 'id' });
|
|
16
13
|
label = input('');
|
|
17
14
|
classList = input([]);
|
|
18
15
|
loading = input(false);
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
_required = input(false, {
|
|
22
|
-
alias: 'required',
|
|
23
|
-
transform: booleanAttribute,
|
|
24
|
-
});
|
|
16
|
+
name = input('');
|
|
17
|
+
placeholder = input('');
|
|
25
18
|
_disabledByInput = input(false, {
|
|
26
|
-
alias: 'disabled',
|
|
27
19
|
transform: booleanAttribute,
|
|
28
20
|
});
|
|
29
|
-
_readonly = input(false, { alias: 'readonly' });
|
|
30
21
|
_disabledByCva = signal(false);
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
get readonly() {
|
|
57
|
-
return this._readonly();
|
|
22
|
+
ngControl = inject(NgControl, {
|
|
23
|
+
self: true,
|
|
24
|
+
optional: true,
|
|
25
|
+
});
|
|
26
|
+
control = new FormControl(null);
|
|
27
|
+
disabled = computed(() => this._disabledByInput() || this._disabledByCva());
|
|
28
|
+
isRequired = signal(this.ngControl?.control?.hasValidator(Validators.required) ?? false);
|
|
29
|
+
hasErrors = signal(false);
|
|
30
|
+
changeSub = new Subscription();
|
|
31
|
+
onChange = () => { };
|
|
32
|
+
onTouched = () => { };
|
|
33
|
+
constructor() {
|
|
34
|
+
if (this.ngControl) {
|
|
35
|
+
this.ngControl.valueAccessor = this;
|
|
36
|
+
}
|
|
37
|
+
effect(() => {
|
|
38
|
+
const inputDisabled = this._disabledByInput();
|
|
39
|
+
const cvaDisabled = this._disabledByCva();
|
|
40
|
+
if (inputDisabled || cvaDisabled) {
|
|
41
|
+
this.control.disable({ emitEvent: false });
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
this.control.enable({ emitEvent: true });
|
|
45
|
+
}
|
|
46
|
+
});
|
|
58
47
|
}
|
|
59
|
-
|
|
60
|
-
const
|
|
61
|
-
|
|
48
|
+
ngOnInit() {
|
|
49
|
+
const parent = this.ngControl?.control;
|
|
50
|
+
if (!parent)
|
|
51
|
+
return;
|
|
52
|
+
parent.statusChanges
|
|
53
|
+
.pipe(startWith(null), takeUntilDestroyed(this.destroyRef))
|
|
54
|
+
.subscribe(() => {
|
|
55
|
+
this.control.setValidators(parent.validator ?? null);
|
|
56
|
+
this.control.setAsyncValidators(parent.asyncValidator ?? null);
|
|
57
|
+
this.control.updateValueAndValidity({ emitEvent: false });
|
|
58
|
+
this.hasErrors.set(parent.invalid && parent.touched);
|
|
59
|
+
this.isRequired.set(parent.hasValidator(Validators.required) ?? false);
|
|
60
|
+
this.cdr.markForCheck();
|
|
61
|
+
});
|
|
62
|
+
parent.events
|
|
63
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
64
|
+
.subscribe((event) => {
|
|
65
|
+
if (event instanceof TouchedChangeEvent) {
|
|
66
|
+
if (parent.touched) {
|
|
67
|
+
this.control.markAsTouched();
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
this.control.markAsUntouched();
|
|
71
|
+
}
|
|
72
|
+
this.hasErrors.set(parent.invalid && parent.touched);
|
|
73
|
+
this.cdr.markForCheck();
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
parent.valueChanges
|
|
77
|
+
.pipe(startWith(null), takeUntilDestroyed(this.destroyRef))
|
|
78
|
+
.subscribe(() => this.cdr.markForCheck());
|
|
62
79
|
}
|
|
63
|
-
|
|
64
|
-
|
|
80
|
+
writeValue(value) {
|
|
81
|
+
this.control.setValue(value, { emitEvent: false });
|
|
65
82
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
}
|
|
71
|
-
control.statusChanges
|
|
83
|
+
registerOnChange(fn) {
|
|
84
|
+
this.onChange = fn;
|
|
85
|
+
this.changeSub.unsubscribe();
|
|
86
|
+
this.changeSub = this.control.valueChanges
|
|
72
87
|
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
73
|
-
.subscribe((
|
|
88
|
+
.subscribe((v) => {
|
|
89
|
+
fn(v);
|
|
90
|
+
});
|
|
74
91
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
}
|
|
92
|
+
registerOnTouched(fn) {
|
|
93
|
+
this.onTouched = fn;
|
|
94
|
+
}
|
|
95
|
+
setDisabledState(isDisabled) {
|
|
96
|
+
this._disabledByCva.set(isDisabled);
|
|
81
97
|
}
|
|
82
|
-
|
|
98
|
+
errorMessage() {
|
|
83
99
|
const control = this.ngControl?.control;
|
|
84
100
|
if (control == null || !control.errors || !control.touched)
|
|
85
101
|
return null;
|
|
@@ -110,13 +126,11 @@ class FormControlBase {
|
|
|
110
126
|
}
|
|
111
127
|
}
|
|
112
128
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormControlBase, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
113
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: FormControlBase, isStandalone: true, inputs: {
|
|
129
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: FormControlBase, isStandalone: true, inputs: { id: { classPropertyName: "id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, _id: { classPropertyName: "_id", publicName: "id", isSignal: true, isRequired: false, transformFunction: null }, label: { classPropertyName: "label", publicName: "label", isSignal: true, isRequired: false, transformFunction: null }, classList: { classPropertyName: "classList", publicName: "classList", isSignal: true, isRequired: false, transformFunction: null }, loading: { classPropertyName: "loading", publicName: "loading", isSignal: true, isRequired: false, transformFunction: null }, name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: false, transformFunction: null }, placeholder: { classPropertyName: "placeholder", publicName: "placeholder", isSignal: true, isRequired: false, transformFunction: null }, _disabledByInput: { classPropertyName: "_disabledByInput", publicName: "_disabledByInput", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0 });
|
|
114
130
|
}
|
|
115
131
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormControlBase, decorators: [{
|
|
116
132
|
type: Directive
|
|
117
|
-
}],
|
|
118
|
-
type: HostBinding
|
|
119
|
-
}] } });
|
|
133
|
+
}], ctorParameters: () => [] });
|
|
120
134
|
|
|
121
135
|
function getControl(controlName, form) {
|
|
122
136
|
if (!form) {
|
|
@@ -177,19 +191,6 @@ function formatNumber(value, locale = 'en-US', options = { maximumFractionDigits
|
|
|
177
191
|
const formatted = numericValue.toLocaleString(locale, options);
|
|
178
192
|
return isNegative ? `-${formatted}` : formatted;
|
|
179
193
|
}
|
|
180
|
-
function formatCurrency(value, locale = 'en-US', options = { maximumFractionDigits: 2 }) {
|
|
181
|
-
if (value == null || value === '') {
|
|
182
|
-
return null;
|
|
183
|
-
}
|
|
184
|
-
if (typeof value !== 'string') {
|
|
185
|
-
value = String(value);
|
|
186
|
-
}
|
|
187
|
-
value = value.replace(/[^\d\-,.]/g, '');
|
|
188
|
-
const isNegative = value.startsWith('-');
|
|
189
|
-
const numericValue = Number(value.replace(/[,$-]/g, ''));
|
|
190
|
-
const formatted = numericValue.toLocaleString(locale, options);
|
|
191
|
-
return isNegative ? `-${formatted}` : formatted;
|
|
192
|
-
}
|
|
193
194
|
|
|
194
195
|
class FormHandlerBase {
|
|
195
196
|
registeredControls = {};
|
|
@@ -215,57 +216,107 @@ class FormHandlerBase {
|
|
|
215
216
|
}
|
|
216
217
|
|
|
217
218
|
class FormMapperBase {
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
219
|
+
fromModel(model) {
|
|
220
|
+
return structuredClone(model);
|
|
221
|
+
}
|
|
222
|
+
toRequest(formValue) {
|
|
223
|
+
return formValue;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
class FormHydrator {
|
|
228
|
+
hydrate(form, model, registry = {}) {
|
|
229
|
+
Object.entries(form.controls).forEach(([key, control]) => {
|
|
230
|
+
if (!(key in model))
|
|
231
|
+
return;
|
|
232
|
+
const mapper = registry[key];
|
|
233
|
+
const value = model?.[key];
|
|
234
|
+
if (control instanceof FormGroup) {
|
|
235
|
+
if (mapper) {
|
|
236
|
+
control.patchValue(mapper.fromModel(value), { emitEvent: false });
|
|
237
|
+
}
|
|
238
|
+
else {
|
|
239
|
+
this.hydrate(control, value, registry);
|
|
240
|
+
}
|
|
241
|
+
return;
|
|
242
|
+
}
|
|
243
|
+
control.patchValue(value, { emitEvent: false });
|
|
244
|
+
});
|
|
222
245
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
246
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormHydrator, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
247
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormHydrator, providedIn: 'root' });
|
|
248
|
+
}
|
|
249
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormHydrator, decorators: [{
|
|
250
|
+
type: Injectable,
|
|
251
|
+
args: [{ providedIn: 'root' }]
|
|
252
|
+
}] });
|
|
253
|
+
|
|
254
|
+
class FormSerializer {
|
|
255
|
+
toRequest(form, registry = {}) {
|
|
256
|
+
const result = {};
|
|
257
|
+
Object.entries(form.controls).forEach(([key, control]) => {
|
|
258
|
+
const mapper = registry[key];
|
|
259
|
+
if (control instanceof FormGroup) {
|
|
260
|
+
if (mapper) {
|
|
261
|
+
result[key] = mapper.toRequest(control.value);
|
|
262
|
+
}
|
|
263
|
+
else {
|
|
264
|
+
result[key] = this.toRequest(control, registry);
|
|
265
|
+
}
|
|
266
|
+
return;
|
|
267
|
+
}
|
|
268
|
+
result[key] = control.value;
|
|
269
|
+
});
|
|
270
|
+
return result;
|
|
226
271
|
}
|
|
272
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormSerializer, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
|
|
273
|
+
static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormSerializer, providedIn: 'root' });
|
|
227
274
|
}
|
|
275
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormSerializer, decorators: [{
|
|
276
|
+
type: Injectable,
|
|
277
|
+
args: [{ providedIn: 'root' }]
|
|
278
|
+
}] });
|
|
228
279
|
|
|
229
|
-
class
|
|
280
|
+
class FormOrchestrator extends FormMapperBase {
|
|
281
|
+
hydrator;
|
|
282
|
+
serializer;
|
|
230
283
|
_form = signal(new FormGroup({}));
|
|
231
|
-
|
|
232
|
-
|
|
284
|
+
_handlers = signal([]);
|
|
285
|
+
_mapperRegistry = signal({});
|
|
233
286
|
_status = signal('idle');
|
|
234
287
|
_errorMessage = signal(null);
|
|
235
|
-
_loadedHandlers = signal(0);
|
|
236
|
-
_allHandlersLoaded = signal(false);
|
|
237
|
-
_logicSubscription = new Subscription();
|
|
238
288
|
form = this._form.asReadonly();
|
|
239
|
-
|
|
240
|
-
|
|
289
|
+
handlers = this._handlers.asReadonly();
|
|
290
|
+
mapperRegistry = this._mapperRegistry.asReadonly();
|
|
241
291
|
status = this._status.asReadonly();
|
|
242
292
|
errorMessage = this._errorMessage.asReadonly();
|
|
293
|
+
_logicSubscription = new Subscription();
|
|
294
|
+
constructor(hydrator, serializer) {
|
|
295
|
+
super();
|
|
296
|
+
this.hydrator = hydrator;
|
|
297
|
+
this.serializer = serializer;
|
|
298
|
+
}
|
|
243
299
|
/**
|
|
244
300
|
* Initializes orchestration state.
|
|
245
301
|
* Must be called before any subform registration or handler execution.
|
|
246
302
|
*/
|
|
247
|
-
|
|
248
|
-
const {
|
|
303
|
+
orchestrate(options) {
|
|
304
|
+
const { form, handlers, mapperRegistry } = options;
|
|
249
305
|
this._form.set(form);
|
|
250
|
-
this.
|
|
251
|
-
this.
|
|
252
|
-
this.
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
this.loadMainHandler();
|
|
256
|
-
}
|
|
306
|
+
this._handlers.set(handlers);
|
|
307
|
+
this._mapperRegistry.set(mapperRegistry);
|
|
308
|
+
Object.values(this.handlers()).forEach((handler) => {
|
|
309
|
+
this.addReactiveLogic(handler.getReactiveLogic(form));
|
|
310
|
+
});
|
|
257
311
|
}
|
|
258
312
|
setForm(form) {
|
|
259
313
|
this._form.set(form);
|
|
260
314
|
}
|
|
261
|
-
|
|
262
|
-
return this.
|
|
315
|
+
getSubForm(key) {
|
|
316
|
+
return this.form().get(key);
|
|
263
317
|
}
|
|
264
|
-
|
|
265
|
-
this.
|
|
266
|
-
...this._subHandlers(),
|
|
267
|
-
[key]: handler,
|
|
268
|
-
});
|
|
318
|
+
addHandler(handler) {
|
|
319
|
+
this._handlers.set([...this._handlers(), handler]);
|
|
269
320
|
}
|
|
270
321
|
addReactiveLogic(subscription) {
|
|
271
322
|
this._logicSubscription.add(subscription);
|
|
@@ -276,53 +327,31 @@ class FormOrchestratorBase {
|
|
|
276
327
|
setErrorMessage(message) {
|
|
277
328
|
this._errorMessage.set(message);
|
|
278
329
|
}
|
|
279
|
-
|
|
280
|
-
this.
|
|
330
|
+
hydrateFromModel(model) {
|
|
331
|
+
const form = this.form();
|
|
332
|
+
const registry = this.mapperRegistry();
|
|
333
|
+
Object.entries(form.controls).forEach(([key, control]) => {
|
|
334
|
+
if (!(key in model))
|
|
335
|
+
return;
|
|
336
|
+
const mapper = registry[key];
|
|
337
|
+
const value = model?.[key];
|
|
338
|
+
if (control instanceof FormGroup) {
|
|
339
|
+
this.hydrator.hydrate(control, mapper ? mapper.fromModel(value) : value);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
281
342
|
}
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
*
|
|
285
|
-
* IMPORTANT:
|
|
286
|
-
* - Handler execution is gated until all registered subhandlers are ready.
|
|
287
|
-
* - Calling order matters; this is lifecycle-sensitive orchestration logic.
|
|
288
|
-
*/
|
|
289
|
-
onSubformReady(subform, groupName, nestGroups = false) {
|
|
290
|
-
if (nestGroups) {
|
|
291
|
-
this.form().setControl(groupName, subform);
|
|
292
|
-
}
|
|
293
|
-
else {
|
|
294
|
-
const keys = Object.keys(subform.controls);
|
|
295
|
-
keys.forEach((key) => {
|
|
296
|
-
this.form().setControl(key, subform.get(key));
|
|
297
|
-
});
|
|
298
|
-
}
|
|
299
|
-
// Prevent duplicate main handler execution when all subhandlers already resolved
|
|
300
|
-
if (this._allHandlersLoaded()) {
|
|
301
|
-
return;
|
|
302
|
-
}
|
|
303
|
-
const subformHandler = this.subHandlers()[groupName];
|
|
304
|
-
if (subformHandler) {
|
|
305
|
-
this._loadedHandlers.set(this._loadedHandlers() + 1);
|
|
306
|
-
this.addReactiveLogic(subformHandler.getReactiveLogic());
|
|
307
|
-
}
|
|
308
|
-
const totalSubHandlers = Object.keys(this.subHandlers()).length;
|
|
309
|
-
const allSubHandlersLoaded = this._loadedHandlers() === totalSubHandlers;
|
|
310
|
-
if (allSubHandlersLoaded && this.mainHandler()) {
|
|
311
|
-
this.loadMainHandler();
|
|
312
|
-
}
|
|
343
|
+
buildRequest() {
|
|
344
|
+
return this.serializer.toRequest(this.form(), this.mapperRegistry());
|
|
313
345
|
}
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
return;
|
|
317
|
-
this.addReactiveLogic(this.mainHandler().getReactiveLogic(this.form()));
|
|
318
|
-
this._allHandlersLoaded.set(true);
|
|
346
|
+
ngOnDestroy() {
|
|
347
|
+
this._logicSubscription.unsubscribe();
|
|
319
348
|
}
|
|
320
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type:
|
|
321
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type:
|
|
349
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormOrchestrator, deps: [{ token: FormHydrator }, { token: FormSerializer }], target: i0.ɵɵFactoryTarget.Directive });
|
|
350
|
+
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "14.0.0", version: "19.2.21", type: FormOrchestrator, isStandalone: true, usesInheritance: true, ngImport: i0 });
|
|
322
351
|
}
|
|
323
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type:
|
|
352
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormOrchestrator, decorators: [{
|
|
324
353
|
type: Directive
|
|
325
|
-
}] });
|
|
354
|
+
}], ctorParameters: () => [{ type: FormHydrator }, { type: FormSerializer }] });
|
|
326
355
|
|
|
327
356
|
/*
|
|
328
357
|
* Public API Surface of core
|
|
@@ -332,5 +361,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
332
361
|
* Generated bundle index. Do not edit.
|
|
333
362
|
*/
|
|
334
363
|
|
|
335
|
-
export { FormControlBase, FormHandlerBase, FormMapperBase,
|
|
364
|
+
export { FormControlBase, FormHandlerBase, FormHydrator, FormMapperBase, FormOrchestrator, FormSerializer, formatNumber, getControl, getControlValue, parseNumber };
|
|
336
365
|
//# sourceMappingURL=ng-modular-forms-core.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ng-modular-forms-core.mjs","sources":["../../../projects/core/src/lib/form-control-base.ts","../../../projects/core/src/lib/form.util.ts","../../../projects/core/src/lib/form-handler-base.ts","../../../projects/core/src/lib/form-mapper-base.ts","../../../projects/core/src/lib/form-orchestrator-base.ts","../../../projects/core/src/public-api.ts","../../../projects/core/src/ng-modular-forms-core.ts"],"sourcesContent":["import { NgControl, Validators } from '@angular/forms';\nimport {\n booleanAttribute,\n ChangeDetectorRef,\n computed,\n DestroyRef,\n Directive,\n DoCheck,\n HostBinding,\n inject,\n input,\n OnInit,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\n\n@Directive()\nexport abstract class FormControlBase<T> implements OnInit, DoCheck {\n static nextId = 0;\n\n @HostBinding()\n id = `nmf-form-control-${FormControlBase.nextId++}`;\n\n protected readonly cdr = inject(ChangeDetectorRef);\n protected readonly destroyRef = inject(DestroyRef);\n\n readonly ngControl = inject(NgControl, {\n optional: true,\n self: true,\n });\n\n readonly label = input<string>('');\n readonly classList = input<string[]>([]);\n readonly loading = input<boolean>(false);\n\n readonly _name = input<string>('', { alias: 'name' });\n readonly _placeholder = input<string>('', { alias: 'placeholder' });\n readonly _required = input<boolean, unknown>(false, {\n alias: 'required',\n transform: booleanAttribute,\n });\n readonly _disabledByInput = input<boolean, unknown>(false, {\n alias: 'disabled',\n transform: booleanAttribute,\n });\n readonly _readonly = input<boolean>(false, { alias: 'readonly' });\n\n protected readonly _disabledByCva = signal(false);\n readonly _disabled = computed(\n () => this._disabledByInput() || this._disabledByCva() || this.loading(),\n );\n\n focused = false;\n\n private lastErrorState = false;\n\n private _value: T | null = null;\n\n get value(): T | null {\n return this._value;\n }\n\n set value(value: T | null) {\n this._value = value;\n this.cdr.markForCheck();\n }\n\n get name(): string {\n return this._name();\n }\n\n get placeholder(): string {\n return this._placeholder();\n }\n\n get required(): boolean {\n const formControl = this.ngControl?.control;\n const required =\n !!formControl && formControl.hasValidator(Validators.required);\n return this._required() || required;\n }\n\n get disabled(): boolean {\n return this._disabled();\n }\n\n get readonly(): boolean {\n return this._readonly();\n }\n\n get errorState(): boolean {\n const control = this.ngControl?.control;\n return !!control && control.invalid && control.touched;\n }\n\n get empty(): boolean {\n return (\n this._value === null || this._value === '' || this._value === undefined\n );\n }\n\n ngOnInit() {\n const control = this.ngControl?.control;\n if (!control) {\n throw new Error(`FormControl ${this.id} not found`);\n }\n\n control.statusChanges\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((val) => this.cdr.markForCheck());\n }\n\n ngDoCheck() {\n const newState = this.errorState;\n\n if (newState !== this.lastErrorState) {\n this.lastErrorState = newState;\n this.cdr.markForCheck();\n }\n }\n\n protected getErrorMessage(): string | null {\n const control = this.ngControl?.control;\n\n if (control == null || !control.errors || !control.touched) return null;\n\n const firstKey = Object.keys(control.errors)[0];\n const error = control.errors[firstKey];\n\n switch (firstKey) {\n case 'required':\n return 'This field is required';\n case 'minlength':\n return `Minimum length is ${error.requiredLength}`;\n case 'maxlength':\n return `Maximum length is ${error.requiredLength}`;\n case 'min':\n return `Minimum value is ${error.min}`;\n case 'max':\n return `Maximum value is ${error.max}`;\n case 'email':\n return 'Invalid email address';\n case 'pattern':\n return 'Invalid format';\n case 'custom':\n if (typeof error === 'string') {\n return error;\n }\n return 'Invalid value';\n default:\n return 'Invalid value';\n }\n }\n}\n","import { FormControl, FormGroup } from '@angular/forms';\n\nexport function getControl<T = unknown>(controlName: string, form: FormGroup) {\n if (!form) {\n throw new Error(\n `Missing form instance while getting the control of \"${controlName}\"`,\n );\n }\n\n const control = form.get(controlName) as FormControl<T>;\n if (!control) {\n throw new Error(`Missing control \"${controlName}\" in form \"${form}\"`);\n }\n\n return control;\n}\n\nexport function getControlValue<T = unknown>(\n controlName: string,\n form: FormGroup,\n): T | null;\n\nexport function getControlValue(\n controlName: string,\n form: FormGroup,\n): number | null;\n\nexport function getControlValue<T = unknown>(\n controlName: string,\n form: FormGroup,\n): T | null {\n const control = getControl<T>(controlName, form);\n if (!control) {\n throw new Error(`Missing control \"${controlName}\" in form \"${form}\"`);\n }\n\n const value = control.getRawValue();\n if (value === '') {\n return null;\n }\n\n if (typeof value === 'string') {\n const cleaned = value.replace(/,/g, '');\n\n if (!Number.isNaN(Number(cleaned))) {\n return parseNumber(value) as T;\n }\n }\n\n return value;\n}\n\nexport function parseNumber(\n input: string | number | null | undefined,\n): number | null {\n if (input == null || input === '') return null;\n\n if (typeof input === 'number') {\n return Number.isFinite(input) ? input : null;\n }\n\n const normalized = input\n .trim()\n .replace(/,/g, '') // remove thousands\n .replace(/(?!^)-/g, ''); // only allow leading '-'\n\n if (normalized === '-' || normalized === '.' || normalized === '-.') {\n return null;\n }\n\n const num = Number(normalized);\n\n return Number.isFinite(num) ? num : null;\n}\n\nexport function formatNumber(\n value: string | number | null,\n locale: string = 'en-US',\n options: Intl.NumberFormatOptions = { maximumFractionDigits: 2 },\n): string | null {\n if (value == null || value === '') {\n return null;\n }\n if (typeof value !== 'string') {\n value = String(value);\n }\n\n value = value.replace(/[^\\d\\-,.]/g, '');\n\n if (value === '') {\n return null;\n }\n\n const isNegative = value.startsWith('-');\n const numericValue = Number(value.replace(/[,$-]/g, ''));\n const formatted = numericValue.toLocaleString(locale, options);\n\n return isNegative ? `-${formatted}` : formatted;\n}\n\nexport function formatCurrency(\n value: string | number | null,\n locale: string = 'en-US',\n options: Intl.NumberFormatOptions = { maximumFractionDigits: 2 },\n): string | null {\n if (value == null || value === '') {\n return null;\n }\n if (typeof value !== 'string') {\n value = String(value);\n }\n\n value = value.replace(/[^\\d\\-,.]/g, '');\n\n const isNegative = value.startsWith('-');\n const numericValue = Number(value.replace(/[,$-]/g, ''));\n const formatted = numericValue.toLocaleString(locale, options);\n\n return isNegative ? `-${formatted}` : formatted;\n}\n","import { FormControl, FormGroup } from '@angular/forms';\nimport { Observable, Subscription } from 'rxjs';\nimport { getControl } from './form.util';\n\nexport abstract class FormHandlerBase<ControlNames extends string = string> {\n abstract getReactiveLogic(form?: FormGroup): Subscription;\n\n protected registeredControls: Record<string, FormControl> = {};\n\n /**\n * Registers form controls for later reactive access.\n */\n registerControls(form: FormGroup, controlNames: ControlNames[]): void {\n controlNames.forEach((cn) => {\n const control = getControl(cn.replace(/_/g, '.'), form);\n\n if (!control) {\n throw new Error(\n `Failed to register control with name: \"${cn}\" in form group: \"${form}\"`,\n );\n }\n\n const key = cn as ControlNames;\n this.registeredControls[key] = control;\n });\n }\n\n valueChangesOf<T>(key: ControlNames): Observable<T> {\n if (!this.registeredControls[key]) {\n throw new Error(\n `Control with name: \"${key}\" not found. Ensure it is registered in registerControls(...)`,\n );\n }\n\n return this.registeredControls[key].valueChanges as Observable<T>;\n }\n}\n","import { FormGroup } from '@angular/forms';\n\nexport abstract class FormMapperBase<\n TModelIn = unknown,\n TModelOut = unknown,\n TFormModel = unknown,\n TStore = Record<string, unknown>,\n> {\n /**\n * Maps form state + external store into an API request payload.\n */\n abstract buildRequest(form: FormGroup, store: TStore): Partial<TModelOut>;\n\n /**\n * Transforms a domain/API model into a form-compatible structure.\n */\n abstract transformFromModel(model: TModelIn): TFormModel;\n\n patchForm(\n form: FormGroup,\n data: TFormModel,\n _context: TStore,\n emitEvent: boolean = false,\n ): void {\n form.patchValue(\n {\n ...(data as Record<string, unknown>),\n },\n { emitEvent },\n );\n }\n\n patchFromModel(form: FormGroup, model: TModelIn, store: TStore): void {\n const formModel = this.transformFromModel(model);\n this.patchForm(form, formModel, store);\n }\n}\n","import { FormGroup } from '@angular/forms';\nimport { Directive, OnDestroy, signal } from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { FormHandlerBase } from './form-handler-base';\n\nexport type FormStatus = 'idle' | 'submitting' | 'error' | 'success';\n\ntype FormHandlerRegistry = Record<string, FormHandlerBase<string>>;\n\ninterface FormOrchestratorOptions {\n mainHandler?: FormHandlerBase<string> | null;\n subHandlers?: FormHandlerRegistry;\n}\n\n@Directive()\nexport abstract class FormOrchestratorBase implements OnDestroy {\n private _form = signal<FormGroup>(new FormGroup({}));\n\n private _mainHandler = signal<FormHandlerBase<string> | null>(null);\n private _subHandlers = signal<FormHandlerRegistry>({});\n\n private _status = signal<FormStatus>('idle');\n private _errorMessage = signal<string | null>(null);\n\n private _loadedHandlers = signal<number>(0);\n private _allHandlersLoaded = signal<boolean>(false);\n\n private _logicSubscription = new Subscription();\n\n public readonly form = this._form.asReadonly();\n public readonly mainHandler = this._mainHandler.asReadonly();\n public readonly subHandlers = this._subHandlers.asReadonly();\n public readonly status = this._status.asReadonly();\n public readonly errorMessage = this._errorMessage.asReadonly();\n\n /**\n * Initializes orchestration state.\n * Must be called before any subform registration or handler execution.\n */\n public initialize(\n form: FormGroup,\n formOrchestratorOptions?: FormOrchestratorOptions,\n ) {\n const { mainHandler, subHandlers = {} } = formOrchestratorOptions ?? {};\n\n this._form.set(form);\n this._mainHandler.set(mainHandler ?? null);\n this._subHandlers.set(subHandlers);\n this._loadedHandlers.set(0);\n\n const subHandlerCount = Object.keys(this.subHandlers());\n if (subHandlerCount.length === 0) {\n this.loadMainHandler();\n }\n }\n\n public setForm(form: FormGroup) {\n this._form.set(form);\n }\n\n public getHandler(key: string): FormHandlerBase<string> | undefined {\n return this.subHandlers()[key];\n }\n\n public setHandler(key: string, handler: FormHandlerBase<string>) {\n this._subHandlers.set({\n ...this._subHandlers(),\n [key]: handler,\n });\n }\n\n public addReactiveLogic(subscription: Subscription) {\n this._logicSubscription.add(subscription);\n }\n\n public setStatus(status: FormStatus) {\n this._status.set(status);\n }\n\n public setErrorMessage(message: string | null) {\n this._errorMessage.set(message);\n }\n\n ngOnDestroy(): void {\n this._logicSubscription.unsubscribe();\n }\n\n /**\n * Registers a subform into the main form tree and coordinates handler execution.\n *\n * IMPORTANT:\n * - Handler execution is gated until all registered subhandlers are ready.\n * - Calling order matters; this is lifecycle-sensitive orchestration logic.\n */\n onSubformReady(\n subform: FormGroup,\n groupName: string,\n nestGroups: boolean = false,\n ): void {\n if (nestGroups) {\n this.form().setControl(groupName, subform);\n } else {\n const keys = Object.keys(subform.controls);\n keys.forEach((key) => {\n this.form().setControl(key, subform.get(key));\n });\n }\n\n // Prevent duplicate main handler execution when all subhandlers already resolved\n if (this._allHandlersLoaded()) {\n return;\n }\n\n const subformHandler = this.subHandlers()[groupName];\n\n if (subformHandler) {\n this._loadedHandlers.set(this._loadedHandlers() + 1);\n this.addReactiveLogic(subformHandler.getReactiveLogic());\n }\n\n const totalSubHandlers = Object.keys(this.subHandlers()).length;\n const allSubHandlersLoaded = this._loadedHandlers() === totalSubHandlers;\n\n if (allSubHandlersLoaded && this.mainHandler()) {\n this.loadMainHandler();\n }\n }\n\n private loadMainHandler() {\n if (!this.mainHandler()) return;\n\n this.addReactiveLogic(this.mainHandler()!.getReactiveLogic(this.form()));\n this._allHandlersLoaded.set(true);\n }\n}\n","/*\n * Public API Surface of core\n */\n\nexport * from './lib/form-control-base';\nexport * from './lib/form-handler-base';\nexport * from './lib/form-mapper-base';\nexport * from './lib/form-orchestrator-base';\nexport * from './lib/form.util';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ng-modular-forms-core.mjs","sources":["../../../projects/core/src/lib/base/form-control-base.ts","../../../projects/core/src/lib/form-util.ts","../../../projects/core/src/lib/base/form-handler-base.ts","../../../projects/core/src/lib/base/form-mapper-base.ts","../../../projects/core/src/lib/form-hydrator.ts","../../../projects/core/src/lib/form-serializer.ts","../../../projects/core/src/lib/form-orchestrator.ts","../../../projects/core/src/public-api.ts","../../../projects/core/src/ng-modular-forms-core.ts"],"sourcesContent":["import {\n ControlValueAccessor,\n FormControl,\n NgControl,\n TouchedChangeEvent,\n Validators,\n} from '@angular/forms';\nimport {\n booleanAttribute,\n ChangeDetectorRef,\n computed,\n DestroyRef,\n Directive,\n effect,\n inject,\n input,\n signal,\n} from '@angular/core';\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\nimport { startWith, Subscription } from 'rxjs';\n\n@Directive()\nexport abstract class FormControlBase<T> implements ControlValueAccessor {\n protected readonly cdr = inject(ChangeDetectorRef);\n protected readonly destroyRef = inject(DestroyRef);\n\n static nextId = 0;\n\n readonly id = input<string | null>(\n `nmf-form-control-${FormControlBase.nextId++}`,\n );\n\n readonly _id = input<string | null>(null, { alias: 'id' });\n readonly label = input<string>('');\n readonly classList = input<string[]>([]);\n readonly loading = input<boolean>(false);\n\n readonly name = input<string>('');\n readonly placeholder = input<string>('');\n readonly _disabledByInput = input<boolean, unknown>(false, {\n transform: booleanAttribute,\n });\n readonly _disabledByCva = signal(false);\n\n readonly ngControl = inject(NgControl, {\n self: true,\n optional: true,\n });\n\n protected readonly control = new FormControl<T | null>(null);\n\n protected readonly disabled = computed(\n () => this._disabledByInput() || this._disabledByCva(),\n );\n\n protected readonly isRequired = signal(\n this.ngControl?.control?.hasValidator(Validators.required) ?? false,\n );\n\n protected readonly hasErrors = signal(false);\n\n private changeSub = new Subscription();\n\n protected onChange: (value: T | null) => void = () => {};\n protected onTouched: () => void = () => {};\n\n constructor() {\n if (this.ngControl) {\n this.ngControl.valueAccessor = this;\n }\n\n effect(() => {\n const inputDisabled = this._disabledByInput();\n const cvaDisabled = this._disabledByCva();\n\n if (inputDisabled || cvaDisabled) {\n this.control.disable({ emitEvent: false });\n } else {\n this.control.enable({ emitEvent: true });\n }\n });\n }\n\n ngOnInit() {\n const parent = this.ngControl?.control;\n if (!parent) return;\n\n parent.statusChanges\n .pipe(startWith(null), takeUntilDestroyed(this.destroyRef))\n .subscribe(() => {\n this.control.setValidators(parent.validator ?? null);\n this.control.setAsyncValidators(parent.asyncValidator ?? null);\n this.control.updateValueAndValidity({ emitEvent: false });\n\n this.hasErrors.set(parent.invalid && parent.touched);\n this.isRequired.set(parent.hasValidator(Validators.required) ?? false);\n\n this.cdr.markForCheck();\n });\n\n parent.events\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((event) => {\n if (event instanceof TouchedChangeEvent) {\n if (parent.touched) {\n this.control.markAsTouched();\n } else {\n this.control.markAsUntouched();\n }\n this.hasErrors.set(parent.invalid && parent.touched);\n this.cdr.markForCheck();\n }\n });\n\n parent.valueChanges\n .pipe(startWith(null), takeUntilDestroyed(this.destroyRef))\n .subscribe(() => this.cdr.markForCheck());\n }\n\n writeValue(value: T): void {\n this.control.setValue(value, { emitEvent: false });\n }\n\n registerOnChange(fn: (value: T | null) => void): void {\n this.onChange = fn;\n\n this.changeSub.unsubscribe();\n this.changeSub = this.control.valueChanges\n .pipe(takeUntilDestroyed(this.destroyRef))\n .subscribe((v) => {\n fn(v);\n });\n }\n\n registerOnTouched(fn: () => void): void {\n this.onTouched = fn;\n }\n\n setDisabledState(isDisabled: boolean): void {\n this._disabledByCva.set(isDisabled);\n }\n\n protected errorMessage(): string | null {\n const control = this.ngControl?.control;\n if (control == null || !control.errors || !control.touched) return null;\n\n const firstKey = Object.keys(control.errors)[0];\n const error = control.errors[firstKey];\n\n switch (firstKey) {\n case 'required':\n return 'This field is required';\n case 'minlength':\n return `Minimum length is ${error.requiredLength}`;\n case 'maxlength':\n return `Maximum length is ${error.requiredLength}`;\n case 'min':\n return `Minimum value is ${error.min}`;\n case 'max':\n return `Maximum value is ${error.max}`;\n case 'email':\n return 'Invalid email address';\n case 'pattern':\n return 'Invalid format';\n case 'custom':\n if (typeof error === 'string') {\n return error;\n }\n return 'Invalid value';\n default:\n return 'Invalid value';\n }\n }\n}\n","import { FormControl, FormGroup } from '@angular/forms';\n\nexport function getControl<T = unknown>(controlName: string, form: FormGroup) {\n if (!form) {\n throw new Error(\n `Missing form instance while getting the control of \"${controlName}\"`,\n );\n }\n\n const control = form.get(controlName) as FormControl<T>;\n if (!control) {\n throw new Error(`Missing control \"${controlName}\" in form \"${form}\"`);\n }\n\n return control;\n}\n\nexport function getControlValue<T = unknown>(\n controlName: string,\n form: FormGroup,\n): T | null;\n\nexport function getControlValue(\n controlName: string,\n form: FormGroup,\n): number | null;\n\nexport function getControlValue<T = unknown>(\n controlName: string,\n form: FormGroup,\n): T | null {\n const control = getControl<T>(controlName, form);\n if (!control) {\n throw new Error(`Missing control \"${controlName}\" in form \"${form}\"`);\n }\n\n const value = control.getRawValue();\n if (value === '') {\n return null;\n }\n\n if (typeof value === 'string') {\n const cleaned = value.replace(/,/g, '');\n\n if (!Number.isNaN(Number(cleaned))) {\n return parseNumber(value) as T;\n }\n }\n\n return value;\n}\n\nexport function parseNumber(\n input: string | number | null | undefined,\n): number | null {\n if (input == null || input === '') return null;\n\n if (typeof input === 'number') {\n return Number.isFinite(input) ? input : null;\n }\n\n const normalized = input\n .trim()\n .replace(/,/g, '') // remove thousands\n .replace(/(?!^)-/g, ''); // only allow leading '-'\n\n if (normalized === '-' || normalized === '.' || normalized === '-.') {\n return null;\n }\n\n const num = Number(normalized);\n\n return Number.isFinite(num) ? num : null;\n}\n\nexport function formatNumber(\n value: string | number | null,\n locale: string = 'en-US',\n options: Intl.NumberFormatOptions = { maximumFractionDigits: 2 },\n): string | null {\n if (value == null || value === '') {\n return null;\n }\n if (typeof value !== 'string') {\n value = String(value);\n }\n\n value = value.replace(/[^\\d\\-,.]/g, '');\n\n if (value === '') {\n return null;\n }\n\n const isNegative = value.startsWith('-');\n const numericValue = Number(value.replace(/[,$-]/g, ''));\n const formatted = numericValue.toLocaleString(locale, options);\n\n return isNegative ? `-${formatted}` : formatted;\n}\n","import { FormControl, FormGroup } from '@angular/forms';\nimport { Observable, Subscription } from 'rxjs';\nimport { getControl } from '../form-util';\n\nexport abstract class FormHandlerBase<ControlNames extends string = string> {\n abstract getReactiveLogic(form: FormGroup): Subscription;\n\n private registeredControls: Record<string, FormControl> = {};\n\n /**\n * Registers form controls for later reactive access.\n */\n registerControls(form: FormGroup, controlNames: ControlNames[]): void {\n controlNames.forEach((cn) => {\n const control = getControl(cn.replace(/_/g, '.'), form);\n\n if (!control) {\n throw new Error(\n `Failed to register control with name: \"${cn}\" in form group: \"${form}\"`,\n );\n }\n\n const key = cn as ControlNames;\n this.registeredControls[key] = control;\n });\n }\n\n valueChangesOf<T>(key: ControlNames): Observable<T> {\n if (!this.registeredControls[key]) {\n throw new Error(\n `Control with name: \"${key}\" not found. Ensure it is registered in registerControls(...)`,\n );\n }\n\n return this.registeredControls[key].valueChanges as Observable<T>;\n }\n}\n","export abstract class FormMapperBase<TIn = unknown, TOut = TIn, TForm = TIn> {\n public fromModel(model: TIn): TForm {\n return structuredClone(model) as unknown as TForm;\n }\n\n public toRequest(formValue: TForm): TOut {\n return formValue as unknown as TOut;\n }\n}\n","import { Injectable } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { MapperRegistry } from './types';\n\n@Injectable({ providedIn: 'root' })\nexport class FormHydrator {\n hydrate(form: FormGroup, model: any, registry: MapperRegistry = {}) {\n Object.entries(form.controls).forEach(([key, control]) => {\n if (!(key in model)) return;\n\n const mapper = registry[key];\n const value = model?.[key];\n\n if (control instanceof FormGroup) {\n if (mapper) {\n control.patchValue(mapper.fromModel(value), { emitEvent: false });\n } else {\n this.hydrate(control, value, registry);\n }\n return;\n }\n\n control.patchValue(value, { emitEvent: false });\n });\n }\n}\n","import { Injectable } from '@angular/core';\nimport { FormGroup } from '@angular/forms';\nimport { MapperRegistry } from './types';\n\n@Injectable({ providedIn: 'root' })\nexport class FormSerializer {\n toRequest(form: FormGroup, registry: MapperRegistry = {}) {\n const result: any = {};\n\n Object.entries(form.controls).forEach(([key, control]) => {\n const mapper = registry[key];\n\n if (control instanceof FormGroup) {\n if (mapper) {\n result[key] = mapper.toRequest(control.value);\n } else {\n result[key] = this.toRequest(control, registry);\n }\n return;\n }\n\n result[key] = control.value;\n });\n\n return result;\n }\n}\n","import { FormGroup } from '@angular/forms';\nimport { Directive, OnDestroy, signal } from '@angular/core';\nimport { Subscription } from 'rxjs';\nimport { FormHandlerBase } from './base/form-handler-base';\nimport { FormMapperBase } from './base/form-mapper-base';\nimport { FormHydrator } from './form-hydrator';\nimport { FormSerializer } from './form-serializer';\nimport {\n FormHandlerRegistry,\n FormOrchestratorOptions,\n FormStatus,\n MapperRegistry,\n} from './types';\n\n@Directive()\nexport abstract class FormOrchestrator\n extends FormMapperBase\n implements OnDestroy\n{\n private readonly _form = signal<FormGroup>(new FormGroup({}));\n private readonly _handlers = signal<FormHandlerRegistry>([]);\n private readonly _mapperRegistry = signal<MapperRegistry>({});\n private readonly _status = signal<FormStatus>('idle');\n private readonly _errorMessage = signal<string | null>(null);\n\n public readonly form = this._form.asReadonly();\n public readonly handlers = this._handlers.asReadonly();\n public readonly mapperRegistry = this._mapperRegistry.asReadonly();\n public readonly status = this._status.asReadonly();\n public readonly errorMessage = this._errorMessage.asReadonly();\n\n private _logicSubscription = new Subscription();\n\n constructor(\n protected readonly hydrator: FormHydrator,\n protected readonly serializer: FormSerializer,\n ) {\n super();\n }\n\n /**\n * Initializes orchestration state.\n * Must be called before any subform registration or handler execution.\n */\n public orchestrate(options: FormOrchestratorOptions) {\n const { form, handlers, mapperRegistry } = options;\n this._form.set(form);\n this._handlers.set(handlers);\n this._mapperRegistry.set(mapperRegistry);\n\n Object.values(this.handlers()).forEach((handler) => {\n this.addReactiveLogic(handler.getReactiveLogic(form));\n });\n }\n\n public setForm(form: FormGroup) {\n this._form.set(form);\n }\n\n public getSubForm(key: string): FormGroup {\n return this.form().get(key) as FormGroup;\n }\n\n public addHandler(handler: FormHandlerBase) {\n this._handlers.set([...this._handlers(), handler]);\n }\n\n public addReactiveLogic(subscription: Subscription) {\n this._logicSubscription.add(subscription);\n }\n\n public setStatus(status: FormStatus) {\n this._status.set(status);\n }\n\n public setErrorMessage(message: string | null) {\n this._errorMessage.set(message);\n }\n\n public hydrateFromModel(model: any) {\n const form = this.form();\n const registry = this.mapperRegistry();\n\n Object.entries(form.controls).forEach(([key, control]) => {\n if (!(key in model)) return;\n\n const mapper = registry[key];\n const value = model?.[key];\n\n if (control instanceof FormGroup) {\n this.hydrator.hydrate(\n control,\n mapper ? mapper.fromModel(value) : value,\n );\n }\n });\n }\n\n public buildRequest(): any {\n return this.serializer.toRequest(this.form(), this.mapperRegistry());\n }\n\n ngOnDestroy(): void {\n this._logicSubscription.unsubscribe();\n }\n}\n","/*\n * Public API Surface of core\n */\n\nexport * from './lib/base/form-control-base';\nexport * from './lib/base/form-handler-base';\nexport * from './lib/base/form-mapper-base';\nexport * from './lib/form-hydrator';\nexport * from './lib/form-orchestrator';\nexport * from './lib/form-serializer';\nexport * from './lib/form-util';\nexport * from './lib/types';\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.FormHydrator","i2.FormSerializer"],"mappings":"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"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { ControlValueAccessor, FormControl, NgControl } from '@angular/forms';
|
|
2
|
+
import { ChangeDetectorRef, DestroyRef } from '@angular/core';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare abstract class FormControlBase<T> implements ControlValueAccessor {
|
|
5
|
+
protected readonly cdr: ChangeDetectorRef;
|
|
6
|
+
protected readonly destroyRef: DestroyRef;
|
|
7
|
+
static nextId: number;
|
|
8
|
+
readonly id: import("@angular/core").InputSignal<string | null>;
|
|
9
|
+
readonly _id: import("@angular/core").InputSignal<string | null>;
|
|
10
|
+
readonly label: import("@angular/core").InputSignal<string>;
|
|
11
|
+
readonly classList: import("@angular/core").InputSignal<string[]>;
|
|
12
|
+
readonly loading: import("@angular/core").InputSignal<boolean>;
|
|
13
|
+
readonly name: import("@angular/core").InputSignal<string>;
|
|
14
|
+
readonly placeholder: import("@angular/core").InputSignal<string>;
|
|
15
|
+
readonly _disabledByInput: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
16
|
+
readonly _disabledByCva: import("@angular/core").WritableSignal<boolean>;
|
|
17
|
+
readonly ngControl: NgControl | null;
|
|
18
|
+
protected readonly control: FormControl<T | null>;
|
|
19
|
+
protected readonly disabled: import("@angular/core").Signal<boolean>;
|
|
20
|
+
protected readonly isRequired: import("@angular/core").WritableSignal<boolean>;
|
|
21
|
+
protected readonly hasErrors: import("@angular/core").WritableSignal<boolean>;
|
|
22
|
+
private changeSub;
|
|
23
|
+
protected onChange: (value: T | null) => void;
|
|
24
|
+
protected onTouched: () => void;
|
|
25
|
+
constructor();
|
|
26
|
+
ngOnInit(): void;
|
|
27
|
+
writeValue(value: T): void;
|
|
28
|
+
registerOnChange(fn: (value: T | null) => void): void;
|
|
29
|
+
registerOnTouched(fn: () => void): void;
|
|
30
|
+
setDisabledState(isDisabled: boolean): void;
|
|
31
|
+
protected errorMessage(): string | null;
|
|
32
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FormControlBase<any>, never>;
|
|
33
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<FormControlBase<any>, never, never, { "id": { "alias": "id"; "required": false; "isSignal": true; }; "_id": { "alias": "id"; "required": false; "isSignal": true; }; "label": { "alias": "label"; "required": false; "isSignal": true; }; "classList": { "alias": "classList"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "name": { "alias": "name"; "required": false; "isSignal": true; }; "placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "_disabledByInput": { "alias": "_disabledByInput"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
34
|
+
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { FormGroup } from '@angular/forms';
|
|
2
2
|
import { Observable, Subscription } from 'rxjs';
|
|
3
3
|
export declare abstract class FormHandlerBase<ControlNames extends string = string> {
|
|
4
|
-
abstract getReactiveLogic(form
|
|
5
|
-
|
|
4
|
+
abstract getReactiveLogic(form: FormGroup): Subscription;
|
|
5
|
+
private registeredControls;
|
|
6
6
|
/**
|
|
7
7
|
* Registers form controls for later reactive access.
|
|
8
8
|
*/
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FormGroup } from '@angular/forms';
|
|
2
|
+
import { MapperRegistry } from './types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class FormHydrator {
|
|
5
|
+
hydrate(form: FormGroup, model: any, registry?: MapperRegistry): void;
|
|
6
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FormHydrator, never>;
|
|
7
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<FormHydrator>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { FormGroup } from '@angular/forms';
|
|
2
|
+
import { OnDestroy } from '@angular/core';
|
|
3
|
+
import { Subscription } from 'rxjs';
|
|
4
|
+
import { FormHandlerBase } from './base/form-handler-base';
|
|
5
|
+
import { FormMapperBase } from './base/form-mapper-base';
|
|
6
|
+
import { FormHydrator } from './form-hydrator';
|
|
7
|
+
import { FormSerializer } from './form-serializer';
|
|
8
|
+
import { FormHandlerRegistry, FormOrchestratorOptions, FormStatus, MapperRegistry } from './types';
|
|
9
|
+
import * as i0 from "@angular/core";
|
|
10
|
+
export declare abstract class FormOrchestrator extends FormMapperBase implements OnDestroy {
|
|
11
|
+
protected readonly hydrator: FormHydrator;
|
|
12
|
+
protected readonly serializer: FormSerializer;
|
|
13
|
+
private readonly _form;
|
|
14
|
+
private readonly _handlers;
|
|
15
|
+
private readonly _mapperRegistry;
|
|
16
|
+
private readonly _status;
|
|
17
|
+
private readonly _errorMessage;
|
|
18
|
+
readonly form: import("@angular/core").Signal<FormGroup<any>>;
|
|
19
|
+
readonly handlers: import("@angular/core").Signal<FormHandlerRegistry>;
|
|
20
|
+
readonly mapperRegistry: import("@angular/core").Signal<MapperRegistry>;
|
|
21
|
+
readonly status: import("@angular/core").Signal<FormStatus>;
|
|
22
|
+
readonly errorMessage: import("@angular/core").Signal<string | null>;
|
|
23
|
+
private _logicSubscription;
|
|
24
|
+
constructor(hydrator: FormHydrator, serializer: FormSerializer);
|
|
25
|
+
/**
|
|
26
|
+
* Initializes orchestration state.
|
|
27
|
+
* Must be called before any subform registration or handler execution.
|
|
28
|
+
*/
|
|
29
|
+
orchestrate(options: FormOrchestratorOptions): void;
|
|
30
|
+
setForm(form: FormGroup): void;
|
|
31
|
+
getSubForm(key: string): FormGroup;
|
|
32
|
+
addHandler(handler: FormHandlerBase): void;
|
|
33
|
+
addReactiveLogic(subscription: Subscription): void;
|
|
34
|
+
setStatus(status: FormStatus): void;
|
|
35
|
+
setErrorMessage(message: string | null): void;
|
|
36
|
+
hydrateFromModel(model: any): void;
|
|
37
|
+
buildRequest(): any;
|
|
38
|
+
ngOnDestroy(): void;
|
|
39
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FormOrchestrator, never>;
|
|
40
|
+
static ɵdir: i0.ɵɵDirectiveDeclaration<FormOrchestrator, never, never, {}, {}, never, never, true, never>;
|
|
41
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { FormGroup } from '@angular/forms';
|
|
2
|
+
import { MapperRegistry } from './types';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
export declare class FormSerializer {
|
|
5
|
+
toRequest(form: FormGroup, registry?: MapperRegistry): any;
|
|
6
|
+
static ɵfac: i0.ɵɵFactoryDeclaration<FormSerializer, never>;
|
|
7
|
+
static ɵprov: i0.ɵɵInjectableDeclaration<FormSerializer>;
|
|
8
|
+
}
|
|
@@ -4,4 +4,3 @@ export declare function getControlValue<T = unknown>(controlName: string, form:
|
|
|
4
4
|
export declare function getControlValue(controlName: string, form: FormGroup): number | null;
|
|
5
5
|
export declare function parseNumber(input: string | number | null | undefined): number | null;
|
|
6
6
|
export declare function formatNumber(value: string | number | null, locale?: string, options?: Intl.NumberFormatOptions): string | null;
|
|
7
|
-
export declare function formatCurrency(value: string | number | null, locale?: string, options?: Intl.NumberFormatOptions): string | null;
|
package/lib/types.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { FormGroup } from '@angular/forms';
|
|
2
|
+
import { FormMapperBase } from './base/form-mapper-base';
|
|
3
|
+
import { FormHandlerBase } from './base/form-handler-base';
|
|
4
|
+
export type FormStatus = 'idle' | 'submitting' | 'error' | 'success';
|
|
5
|
+
export type MapperRegistry = Record<string, FormMapperBase<any, any, any>>;
|
|
6
|
+
export type FormHandlerRegistry = FormHandlerBase[];
|
|
7
|
+
export interface FormOrchestratorOptions {
|
|
8
|
+
form: FormGroup;
|
|
9
|
+
handlers: FormHandlerRegistry;
|
|
10
|
+
mapperRegistry: MapperRegistry;
|
|
11
|
+
}
|
package/package.json
CHANGED
package/public-api.d.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
-
export * from './lib/form-control-base';
|
|
2
|
-
export * from './lib/form-handler-base';
|
|
3
|
-
export * from './lib/form-mapper-base';
|
|
4
|
-
export * from './lib/form-
|
|
5
|
-
export * from './lib/form
|
|
1
|
+
export * from './lib/base/form-control-base';
|
|
2
|
+
export * from './lib/base/form-handler-base';
|
|
3
|
+
export * from './lib/base/form-mapper-base';
|
|
4
|
+
export * from './lib/form-hydrator';
|
|
5
|
+
export * from './lib/form-orchestrator';
|
|
6
|
+
export * from './lib/form-serializer';
|
|
7
|
+
export * from './lib/form-util';
|
|
8
|
+
export * from './lib/types';
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { NgControl } from '@angular/forms';
|
|
2
|
-
import { ChangeDetectorRef, DestroyRef, DoCheck, OnInit } from '@angular/core';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
export declare abstract class FormControlBase<T> implements OnInit, DoCheck {
|
|
5
|
-
static nextId: number;
|
|
6
|
-
id: string;
|
|
7
|
-
protected readonly cdr: ChangeDetectorRef;
|
|
8
|
-
protected readonly destroyRef: DestroyRef;
|
|
9
|
-
readonly ngControl: NgControl | null;
|
|
10
|
-
readonly label: import("@angular/core").InputSignal<string>;
|
|
11
|
-
readonly classList: import("@angular/core").InputSignal<string[]>;
|
|
12
|
-
readonly loading: import("@angular/core").InputSignal<boolean>;
|
|
13
|
-
readonly _name: import("@angular/core").InputSignal<string>;
|
|
14
|
-
readonly _placeholder: import("@angular/core").InputSignal<string>;
|
|
15
|
-
readonly _required: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
16
|
-
readonly _disabledByInput: import("@angular/core").InputSignalWithTransform<boolean, unknown>;
|
|
17
|
-
readonly _readonly: import("@angular/core").InputSignal<boolean>;
|
|
18
|
-
protected readonly _disabledByCva: import("@angular/core").WritableSignal<boolean>;
|
|
19
|
-
readonly _disabled: import("@angular/core").Signal<boolean>;
|
|
20
|
-
focused: boolean;
|
|
21
|
-
private lastErrorState;
|
|
22
|
-
private _value;
|
|
23
|
-
get value(): T | null;
|
|
24
|
-
set value(value: T | null);
|
|
25
|
-
get name(): string;
|
|
26
|
-
get placeholder(): string;
|
|
27
|
-
get required(): boolean;
|
|
28
|
-
get disabled(): boolean;
|
|
29
|
-
get readonly(): boolean;
|
|
30
|
-
get errorState(): boolean;
|
|
31
|
-
get empty(): boolean;
|
|
32
|
-
ngOnInit(): void;
|
|
33
|
-
ngDoCheck(): void;
|
|
34
|
-
protected getErrorMessage(): string | null;
|
|
35
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<FormControlBase<any>, never>;
|
|
36
|
-
static ɵdir: i0.ɵɵDirectiveDeclaration<FormControlBase<any>, never, never, { "label": { "alias": "label"; "required": false; "isSignal": true; }; "classList": { "alias": "classList"; "required": false; "isSignal": true; }; "loading": { "alias": "loading"; "required": false; "isSignal": true; }; "_name": { "alias": "name"; "required": false; "isSignal": true; }; "_placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "_required": { "alias": "required"; "required": false; "isSignal": true; }; "_disabledByInput": { "alias": "disabled"; "required": false; "isSignal": true; }; "_readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; }, {}, never, never, true, never>;
|
|
37
|
-
}
|
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
import { FormGroup } from '@angular/forms';
|
|
2
|
-
export declare abstract class FormMapperBase<TModelIn = unknown, TModelOut = unknown, TFormModel = unknown, TStore = Record<string, unknown>> {
|
|
3
|
-
/**
|
|
4
|
-
* Maps form state + external store into an API request payload.
|
|
5
|
-
*/
|
|
6
|
-
abstract buildRequest(form: FormGroup, store: TStore): Partial<TModelOut>;
|
|
7
|
-
/**
|
|
8
|
-
* Transforms a domain/API model into a form-compatible structure.
|
|
9
|
-
*/
|
|
10
|
-
abstract transformFromModel(model: TModelIn): TFormModel;
|
|
11
|
-
patchForm(form: FormGroup, data: TFormModel, _context: TStore, emitEvent?: boolean): void;
|
|
12
|
-
patchFromModel(form: FormGroup, model: TModelIn, store: TStore): void;
|
|
13
|
-
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
import { FormGroup } from '@angular/forms';
|
|
2
|
-
import { OnDestroy } from '@angular/core';
|
|
3
|
-
import { Subscription } from 'rxjs';
|
|
4
|
-
import { FormHandlerBase } from './form-handler-base';
|
|
5
|
-
import * as i0 from "@angular/core";
|
|
6
|
-
export type FormStatus = 'idle' | 'submitting' | 'error' | 'success';
|
|
7
|
-
type FormHandlerRegistry = Record<string, FormHandlerBase<string>>;
|
|
8
|
-
interface FormOrchestratorOptions {
|
|
9
|
-
mainHandler?: FormHandlerBase<string> | null;
|
|
10
|
-
subHandlers?: FormHandlerRegistry;
|
|
11
|
-
}
|
|
12
|
-
export declare abstract class FormOrchestratorBase implements OnDestroy {
|
|
13
|
-
private _form;
|
|
14
|
-
private _mainHandler;
|
|
15
|
-
private _subHandlers;
|
|
16
|
-
private _status;
|
|
17
|
-
private _errorMessage;
|
|
18
|
-
private _loadedHandlers;
|
|
19
|
-
private _allHandlersLoaded;
|
|
20
|
-
private _logicSubscription;
|
|
21
|
-
readonly form: import("@angular/core").Signal<FormGroup<any>>;
|
|
22
|
-
readonly mainHandler: import("@angular/core").Signal<FormHandlerBase<string> | null>;
|
|
23
|
-
readonly subHandlers: import("@angular/core").Signal<FormHandlerRegistry>;
|
|
24
|
-
readonly status: import("@angular/core").Signal<FormStatus>;
|
|
25
|
-
readonly errorMessage: import("@angular/core").Signal<string | null>;
|
|
26
|
-
/**
|
|
27
|
-
* Initializes orchestration state.
|
|
28
|
-
* Must be called before any subform registration or handler execution.
|
|
29
|
-
*/
|
|
30
|
-
initialize(form: FormGroup, formOrchestratorOptions?: FormOrchestratorOptions): void;
|
|
31
|
-
setForm(form: FormGroup): void;
|
|
32
|
-
getHandler(key: string): FormHandlerBase<string> | undefined;
|
|
33
|
-
setHandler(key: string, handler: FormHandlerBase<string>): void;
|
|
34
|
-
addReactiveLogic(subscription: Subscription): void;
|
|
35
|
-
setStatus(status: FormStatus): void;
|
|
36
|
-
setErrorMessage(message: string | null): void;
|
|
37
|
-
ngOnDestroy(): void;
|
|
38
|
-
/**
|
|
39
|
-
* Registers a subform into the main form tree and coordinates handler execution.
|
|
40
|
-
*
|
|
41
|
-
* IMPORTANT:
|
|
42
|
-
* - Handler execution is gated until all registered subhandlers are ready.
|
|
43
|
-
* - Calling order matters; this is lifecycle-sensitive orchestration logic.
|
|
44
|
-
*/
|
|
45
|
-
onSubformReady(subform: FormGroup, groupName: string, nestGroups?: boolean): void;
|
|
46
|
-
private loadMainHandler;
|
|
47
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<FormOrchestratorBase, never>;
|
|
48
|
-
static ɵdir: i0.ɵɵDirectiveDeclaration<FormOrchestratorBase, never, never, {}, {}, never, never, true, never>;
|
|
49
|
-
}
|
|
50
|
-
export {};
|