@ng-modular-forms/core 0.3.1 → 0.5.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/LICENSE +21 -21
- package/README.md +115 -125
- package/fesm2022/ng-modular-forms-core.mjs +223 -184
- 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} +2 -1
- package/lib/types.d.ts +11 -0
- package/package.json +1 -1
- package/public-api.d.ts +8 -6
- package/lib/form-control-base.d.ts +0 -21
- package/lib/form-control-value-assessor.d.ts +0 -37
- package/lib/form-mapper-base.d.ts +0 -13
- package/lib/form-orchestrator-base.d.ts +0 -50
package/LICENSE
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
|
-
MIT License
|
|
2
|
-
|
|
3
|
-
Copyright (c) 2026 Ron Bodnar
|
|
4
|
-
|
|
5
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
-
in the Software without restriction, including without limitation the rights
|
|
8
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
-
furnished to do so, subject to the following conditions:
|
|
11
|
-
|
|
12
|
-
The above copyright notice and this permission notice shall be included in all
|
|
13
|
-
copies or substantial portions of the Software.
|
|
14
|
-
|
|
15
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
-
SOFTWARE.
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Ron Bodnar
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -1,125 +1,115 @@
|
|
|
1
|
-
# @ng-modular-forms/core
|
|
2
|
-
|
|
3
|
-
Core primitives for orchestrating complex Angular reactive forms.
|
|
4
|
-
|
|
5
|
-
## What This Provides
|
|
6
|
-
|
|
7
|
-
- Form orchestration
|
|
8
|
-
- Reactive logic isolation
|
|
9
|
-
- Data mapping layer
|
|
10
|
-
|
|
11
|
-
## Installation
|
|
12
|
-
|
|
13
|
-
```bash
|
|
14
|
-
npm install @ng-modular-forms/core
|
|
15
|
-
```
|
|
16
|
-
|
|
17
|
-
## Key Concepts
|
|
18
|
-
|
|
19
|
-
### FormOrchestratorBase
|
|
20
|
-
|
|
21
|
-
Coordinates form structure and lifecycle.
|
|
22
|
-
|
|
23
|
-
```ts
|
|
24
|
-
@Component({...})
|
|
25
|
-
export class ExampleComponent extends FormOrchestratorBase {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
const
|
|
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
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
---
|
|
102
|
-
|
|
103
|
-
###
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
Use:
|
|
118
|
-
|
|
119
|
-
- @ng-modular-forms/behavior
|
|
120
|
-
- @ng-modular-forms/input
|
|
121
|
-
- @ng-modular-forms/material
|
|
122
|
-
|
|
123
|
-
## License
|
|
124
|
-
|
|
125
|
-
MIT
|
|
1
|
+
# @ng-modular-forms/core
|
|
2
|
+
|
|
3
|
+
Core primitives for orchestrating complex Angular reactive forms.
|
|
4
|
+
|
|
5
|
+
## What This Provides
|
|
6
|
+
|
|
7
|
+
- Form orchestration
|
|
8
|
+
- Reactive logic isolation
|
|
9
|
+
- Data mapping layer
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npm install @ng-modular-forms/core
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Key Concepts
|
|
18
|
+
|
|
19
|
+
### FormOrchestratorBase
|
|
20
|
+
|
|
21
|
+
Coordinates form structure and lifecycle.
|
|
22
|
+
|
|
23
|
+
```ts
|
|
24
|
+
@Component({...})
|
|
25
|
+
export class ExampleComponent extends FormOrchestratorBase {
|
|
26
|
+
|
|
27
|
+
ngOnInit() {
|
|
28
|
+
// Handlers are not required if there is no reactive logic or value change subscriptions.
|
|
29
|
+
const mainHandler = inject(ExampleFormHandler);
|
|
30
|
+
const sectionAHandler = inject(SectionAHandler);
|
|
31
|
+
|
|
32
|
+
form = new FormGroup({});
|
|
33
|
+
handlers = [mainHandler, sectionAHandler]
|
|
34
|
+
|
|
35
|
+
this.initialize(form, handlers);
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
---
|
|
41
|
+
|
|
42
|
+
### FormHandlerBase
|
|
43
|
+
|
|
44
|
+
Encapsulates reactive logic.
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
const CONTROL_NAMES = ["fieldA", "dependentField"] as const;
|
|
48
|
+
|
|
49
|
+
type ControlNames = (typeof CONTROL_NAMES)[number];
|
|
50
|
+
|
|
51
|
+
@Injectable()
|
|
52
|
+
export class SectionAHandler extends FormHandlerBase<ControlNames> {
|
|
53
|
+
override getReactiveLogic(form?: FormGroup): Subscription {
|
|
54
|
+
this.registerControls(form, [...CONTROL_NAMES]);
|
|
55
|
+
|
|
56
|
+
return this.valueChangesOf("fieldA").subscribe((value) => {
|
|
57
|
+
if (value) {
|
|
58
|
+
this.controls.dependentField.enable();
|
|
59
|
+
} else {
|
|
60
|
+
this.controls.dependentField.disable();
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### FormMapperBase
|
|
70
|
+
|
|
71
|
+
Handles transformations between API and form.
|
|
72
|
+
|
|
73
|
+
```ts
|
|
74
|
+
export class ExampleMapper extends FormMapperBase<ApiModel, RequestModel> {
|
|
75
|
+
buildRequest(form: FormGroup) {
|
|
76
|
+
return {
|
|
77
|
+
fieldA: form.value.fieldA,
|
|
78
|
+
fieldB: form.value.fieldB,
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
transformFromModel(model: ApiModel) {
|
|
83
|
+
return {
|
|
84
|
+
fieldA: model.fieldA,
|
|
85
|
+
fieldB: model.fieldB,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
---
|
|
92
|
+
|
|
93
|
+
### Responsibility Boundaries
|
|
94
|
+
|
|
95
|
+
| Layer | Responsibility |
|
|
96
|
+
| :--------------- | :------------------------------------------------------- |
|
|
97
|
+
| **Orchestrator** | Manages form composition and lifecycle coordination. |
|
|
98
|
+
| **Handler** | Encapsulates all reactive logic and stream management. |
|
|
99
|
+
| **Mapper** | Handles data transformation between API and Form states. |
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
### No UI Included
|
|
104
|
+
|
|
105
|
+
This package does **not** provide UI components.
|
|
106
|
+
|
|
107
|
+
Use:
|
|
108
|
+
|
|
109
|
+
- @ng-modular-forms/behavior
|
|
110
|
+
- @ng-modular-forms/input
|
|
111
|
+
- @ng-modular-forms/material
|
|
112
|
+
|
|
113
|
+
## License
|
|
114
|
+
|
|
115
|
+
MIT
|
|
@@ -1,119 +1,104 @@
|
|
|
1
|
+
import { NgControl, FormControl, Validators, TouchedChangeEvent, FormGroup } from '@angular/forms';
|
|
1
2
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ChangeDetectorRef, input,
|
|
3
|
-
import * as i1 from '@angular/forms';
|
|
4
|
-
import { FormGroup, FormGroupDirective, Validators } from '@angular/forms';
|
|
3
|
+
import { inject, ChangeDetectorRef, DestroyRef, input, booleanAttribute, signal, computed, effect, Directive, Injectable } from '@angular/core';
|
|
5
4
|
import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
|
|
6
|
-
import { Subscription } from 'rxjs';
|
|
5
|
+
import { Subscription, startWith } from 'rxjs';
|
|
7
6
|
|
|
8
|
-
|
|
9
|
-
* Base implementation for custom form controls that integrate with Angular Reactive Forms (ControlValueAccessor)
|
|
10
|
-
*
|
|
11
|
-
* NOTE: This class is UI-layer only and should not be used in form orchestration logic.
|
|
12
|
-
*/
|
|
13
|
-
class FormControlValueAccessor {
|
|
14
|
-
ngControl;
|
|
15
|
-
elementRef;
|
|
7
|
+
class FormControlBase {
|
|
16
8
|
cdr = inject(ChangeDetectorRef);
|
|
17
|
-
|
|
18
|
-
_placeholder = input('', { alias: 'placeholder' });
|
|
19
|
-
_required = input(false, { alias: 'required' });
|
|
20
|
-
_disabled = input(false, { alias: 'disabled' });
|
|
21
|
-
_readonly = input(false, { alias: 'readonly' });
|
|
22
|
-
formControlName = input('');
|
|
23
|
-
get name() {
|
|
24
|
-
return this._name();
|
|
25
|
-
}
|
|
26
|
-
get placeholder() {
|
|
27
|
-
return this._placeholder();
|
|
28
|
-
}
|
|
29
|
-
get required() {
|
|
30
|
-
return this._required();
|
|
31
|
-
}
|
|
32
|
-
get disabled() {
|
|
33
|
-
return this._disabled();
|
|
34
|
-
}
|
|
35
|
-
get readonly() {
|
|
36
|
-
return this._readonly();
|
|
37
|
-
}
|
|
9
|
+
destroyRef = inject(DestroyRef);
|
|
38
10
|
static nextId = 0;
|
|
39
|
-
id = `nmf-form-control-${
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
11
|
+
id = input(`nmf-form-control-${FormControlBase.nextId++}`);
|
|
12
|
+
_id = input(null, { alias: 'id' });
|
|
13
|
+
label = input('');
|
|
14
|
+
classList = input([]);
|
|
15
|
+
loading = input(false);
|
|
16
|
+
name = input('');
|
|
17
|
+
placeholder = input('');
|
|
18
|
+
_disabledByInput = input(false, {
|
|
19
|
+
transform: booleanAttribute,
|
|
20
|
+
});
|
|
21
|
+
_disabledByCva = signal(false);
|
|
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 = () => { };
|
|
48
32
|
onTouched = () => { };
|
|
49
|
-
constructor(
|
|
50
|
-
this.ngControl
|
|
51
|
-
this.elementRef = elementRef;
|
|
52
|
-
if (this.ngControl != null) {
|
|
33
|
+
constructor() {
|
|
34
|
+
if (this.ngControl) {
|
|
53
35
|
this.ngControl.valueAccessor = this;
|
|
54
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
|
+
});
|
|
47
|
+
}
|
|
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());
|
|
55
79
|
}
|
|
56
80
|
writeValue(value) {
|
|
57
|
-
this.
|
|
58
|
-
this.cdr.markForCheck();
|
|
81
|
+
this.control.setValue(value, { emitEvent: false });
|
|
59
82
|
}
|
|
60
83
|
registerOnChange(fn) {
|
|
61
84
|
this.onChange = fn;
|
|
85
|
+
this.changeSub.unsubscribe();
|
|
86
|
+
this.changeSub = this.control.valueChanges
|
|
87
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
88
|
+
.subscribe((v) => {
|
|
89
|
+
fn(v);
|
|
90
|
+
});
|
|
62
91
|
}
|
|
63
92
|
registerOnTouched(fn) {
|
|
64
93
|
this.onTouched = fn;
|
|
65
94
|
}
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormControlValueAccessor, decorators: [{
|
|
70
|
-
type: Directive
|
|
71
|
-
}], ctorParameters: () => [{ type: i1.NgControl, decorators: [{
|
|
72
|
-
type: Optional
|
|
73
|
-
}, {
|
|
74
|
-
type: Self
|
|
75
|
-
}] }, { type: i0.ElementRef }], propDecorators: { id: [{
|
|
76
|
-
type: HostBinding
|
|
77
|
-
}] } });
|
|
78
|
-
|
|
79
|
-
class FormControlBase extends FormControlValueAccessor {
|
|
80
|
-
label = input('');
|
|
81
|
-
classList = input([]);
|
|
82
|
-
loading = input(false);
|
|
83
|
-
_form = signal(new FormGroup({}));
|
|
84
|
-
_controlName = signal('');
|
|
85
|
-
form = this._form.asReadonly();
|
|
86
|
-
controlName = this._controlName.asReadonly();
|
|
87
|
-
control = computed(() => this._form().get(this._controlName()));
|
|
88
|
-
parentFormGroup = inject(FormGroupDirective, {
|
|
89
|
-
optional: true,
|
|
90
|
-
host: true,
|
|
91
|
-
});
|
|
92
|
-
ngOnInit() {
|
|
93
|
-
const controlName = this.formControlName() ?? 'default';
|
|
94
|
-
const form = this.parentFormGroup?.form;
|
|
95
|
-
if (!form) {
|
|
96
|
-
throw new Error(`FormGroupDirective not found. Ensure component is used inside a form group`);
|
|
97
|
-
}
|
|
98
|
-
this._form.set(form);
|
|
99
|
-
this._controlName.set(controlName);
|
|
100
|
-
const control = form.get(controlName);
|
|
101
|
-
if (!control) {
|
|
102
|
-
throw new Error(`FormControl '${controlName}' not found in parent FormGroup`);
|
|
103
|
-
}
|
|
104
|
-
control.statusChanges
|
|
105
|
-
.pipe(takeUntilDestroyed())
|
|
106
|
-
.subscribe(() => this.cdr.markForCheck());
|
|
95
|
+
setDisabledState(isDisabled) {
|
|
96
|
+
this._disabledByCva.set(isDisabled);
|
|
107
97
|
}
|
|
108
|
-
|
|
109
|
-
const control = this.
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
serverError = computed(() => this.form()?.errors?.['server']);
|
|
113
|
-
getErrorMessage() {
|
|
114
|
-
const control = this._form()?.get(this._controlName());
|
|
115
|
-
if (!control || !control.errors || !control.touched)
|
|
116
|
-
return '';
|
|
98
|
+
errorMessage() {
|
|
99
|
+
const control = this.ngControl?.control;
|
|
100
|
+
if (control == null || !control.errors || !control.touched)
|
|
101
|
+
return null;
|
|
117
102
|
const firstKey = Object.keys(control.errors)[0];
|
|
118
103
|
const error = control.errors[firstKey];
|
|
119
104
|
switch (firstKey) {
|
|
@@ -131,18 +116,21 @@ class FormControlBase extends FormControlValueAccessor {
|
|
|
131
116
|
return 'Invalid email address';
|
|
132
117
|
case 'pattern':
|
|
133
118
|
return 'Invalid format';
|
|
134
|
-
case '
|
|
135
|
-
|
|
119
|
+
case 'custom':
|
|
120
|
+
if (typeof error === 'string') {
|
|
121
|
+
return error;
|
|
122
|
+
}
|
|
123
|
+
return 'Invalid value';
|
|
136
124
|
default:
|
|
137
125
|
return 'Invalid value';
|
|
138
126
|
}
|
|
139
127
|
}
|
|
140
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormControlBase, deps:
|
|
141
|
-
static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.2.21", type: FormControlBase, isStandalone: true, inputs: { 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 } },
|
|
128
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormControlBase, deps: [], target: i0.ɵɵFactoryTarget.Directive });
|
|
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 });
|
|
142
130
|
}
|
|
143
131
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type: FormControlBase, decorators: [{
|
|
144
132
|
type: Directive
|
|
145
|
-
}] });
|
|
133
|
+
}], ctorParameters: () => [] });
|
|
146
134
|
|
|
147
135
|
function getControl(controlName, form) {
|
|
148
136
|
if (!form) {
|
|
@@ -166,19 +154,42 @@ function getControlValue(controlName, form) {
|
|
|
166
154
|
if (typeof value === 'string') {
|
|
167
155
|
const cleaned = value.replace(/,/g, '');
|
|
168
156
|
if (!Number.isNaN(Number(cleaned))) {
|
|
169
|
-
return
|
|
157
|
+
return parseNumber(value);
|
|
170
158
|
}
|
|
171
159
|
}
|
|
172
160
|
return value;
|
|
173
161
|
}
|
|
174
|
-
function
|
|
175
|
-
if (
|
|
176
|
-
return
|
|
162
|
+
function parseNumber(input) {
|
|
163
|
+
if (input == null || input === '')
|
|
164
|
+
return null;
|
|
165
|
+
if (typeof input === 'number') {
|
|
166
|
+
return Number.isFinite(input) ? input : null;
|
|
167
|
+
}
|
|
168
|
+
const normalized = input
|
|
169
|
+
.trim()
|
|
170
|
+
.replace(/,/g, '') // remove thousands
|
|
171
|
+
.replace(/(?!^)-/g, ''); // only allow leading '-'
|
|
172
|
+
if (normalized === '-' || normalized === '.' || normalized === '-.') {
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
const num = Number(normalized);
|
|
176
|
+
return Number.isFinite(num) ? num : null;
|
|
177
|
+
}
|
|
178
|
+
function formatNumber(value, locale = 'en-US', options = { maximumFractionDigits: 2 }) {
|
|
179
|
+
if (value == null || value === '') {
|
|
180
|
+
return null;
|
|
177
181
|
}
|
|
178
|
-
if (typeof
|
|
179
|
-
|
|
182
|
+
if (typeof value !== 'string') {
|
|
183
|
+
value = String(value);
|
|
180
184
|
}
|
|
181
|
-
|
|
185
|
+
value = value.replace(/[^\d\-,.]/g, '');
|
|
186
|
+
if (value === '') {
|
|
187
|
+
return null;
|
|
188
|
+
}
|
|
189
|
+
const isNegative = value.startsWith('-');
|
|
190
|
+
const numericValue = Number(value.replace(/[,$-]/g, ''));
|
|
191
|
+
const formatted = numericValue.toLocaleString(locale, options);
|
|
192
|
+
return isNegative ? `-${formatted}` : formatted;
|
|
182
193
|
}
|
|
183
194
|
|
|
184
195
|
class FormHandlerBase {
|
|
@@ -205,57 +216,107 @@ class FormHandlerBase {
|
|
|
205
216
|
}
|
|
206
217
|
|
|
207
218
|
class FormMapperBase {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
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
|
+
});
|
|
212
245
|
}
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
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;
|
|
216
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' });
|
|
217
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
|
+
}] });
|
|
218
279
|
|
|
219
|
-
class
|
|
280
|
+
class FormOrchestrator extends FormMapperBase {
|
|
281
|
+
hydrator;
|
|
282
|
+
serializer;
|
|
220
283
|
_form = signal(new FormGroup({}));
|
|
221
|
-
|
|
222
|
-
|
|
284
|
+
_handlers = signal([]);
|
|
285
|
+
_mapperRegistry = signal({});
|
|
223
286
|
_status = signal('idle');
|
|
224
287
|
_errorMessage = signal(null);
|
|
225
|
-
_loadedHandlers = signal(0);
|
|
226
|
-
_allHandlersLoaded = signal(false);
|
|
227
|
-
_logicSubscription = new Subscription();
|
|
228
288
|
form = this._form.asReadonly();
|
|
229
|
-
|
|
230
|
-
|
|
289
|
+
handlers = this._handlers.asReadonly();
|
|
290
|
+
mapperRegistry = this._mapperRegistry.asReadonly();
|
|
231
291
|
status = this._status.asReadonly();
|
|
232
292
|
errorMessage = this._errorMessage.asReadonly();
|
|
293
|
+
_logicSubscription = new Subscription();
|
|
294
|
+
constructor(hydrator, serializer) {
|
|
295
|
+
super();
|
|
296
|
+
this.hydrator = hydrator;
|
|
297
|
+
this.serializer = serializer;
|
|
298
|
+
}
|
|
233
299
|
/**
|
|
234
300
|
* Initializes orchestration state.
|
|
235
301
|
* Must be called before any subform registration or handler execution.
|
|
236
302
|
*/
|
|
237
|
-
|
|
238
|
-
const {
|
|
303
|
+
orchestrate(options) {
|
|
304
|
+
const { form, handlers, mapperRegistry } = options;
|
|
239
305
|
this._form.set(form);
|
|
240
|
-
this.
|
|
241
|
-
this.
|
|
242
|
-
this.
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
this.loadMainHandler();
|
|
246
|
-
}
|
|
306
|
+
this._handlers.set(handlers);
|
|
307
|
+
this._mapperRegistry.set(mapperRegistry);
|
|
308
|
+
Object.values(this.handlers()).forEach((handler) => {
|
|
309
|
+
this.addReactiveLogic(handler.getReactiveLogic(form));
|
|
310
|
+
});
|
|
247
311
|
}
|
|
248
312
|
setForm(form) {
|
|
249
313
|
this._form.set(form);
|
|
250
314
|
}
|
|
251
|
-
|
|
252
|
-
return this.
|
|
315
|
+
getSubForm(key) {
|
|
316
|
+
return this.form().get(key);
|
|
253
317
|
}
|
|
254
|
-
|
|
255
|
-
this.
|
|
256
|
-
...this._subHandlers(),
|
|
257
|
-
[key]: handler,
|
|
258
|
-
});
|
|
318
|
+
addHandler(handler) {
|
|
319
|
+
this._handlers.set([...this._handlers(), handler]);
|
|
259
320
|
}
|
|
260
321
|
addReactiveLogic(subscription) {
|
|
261
322
|
this._logicSubscription.add(subscription);
|
|
@@ -266,53 +327,31 @@ class FormOrchestratorBase {
|
|
|
266
327
|
setErrorMessage(message) {
|
|
267
328
|
this._errorMessage.set(message);
|
|
268
329
|
}
|
|
269
|
-
|
|
270
|
-
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
|
+
});
|
|
271
342
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
*
|
|
275
|
-
* IMPORTANT:
|
|
276
|
-
* - Handler execution is gated until all registered subhandlers are ready.
|
|
277
|
-
* - Calling order matters; this is lifecycle-sensitive orchestration logic.
|
|
278
|
-
*/
|
|
279
|
-
onSubformReady(subform, groupName, nestGroups = false) {
|
|
280
|
-
if (nestGroups) {
|
|
281
|
-
this.form().setControl(groupName, subform);
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
const keys = Object.keys(subform.controls);
|
|
285
|
-
keys.forEach((key) => {
|
|
286
|
-
this.form().setControl(key, subform.get(key));
|
|
287
|
-
});
|
|
288
|
-
}
|
|
289
|
-
// Prevent duplicate main handler execution when all subhandlers already resolved
|
|
290
|
-
if (this._allHandlersLoaded()) {
|
|
291
|
-
return;
|
|
292
|
-
}
|
|
293
|
-
const subformHandler = this.subHandlers()[groupName];
|
|
294
|
-
if (subformHandler) {
|
|
295
|
-
this._loadedHandlers.set(this._loadedHandlers() + 1);
|
|
296
|
-
this.addReactiveLogic(subformHandler.getReactiveLogic());
|
|
297
|
-
}
|
|
298
|
-
const totalSubHandlers = Object.keys(this.subHandlers()).length;
|
|
299
|
-
const allSubHandlersLoaded = this._loadedHandlers() === totalSubHandlers;
|
|
300
|
-
if (allSubHandlersLoaded && this.mainHandler()) {
|
|
301
|
-
this.loadMainHandler();
|
|
302
|
-
}
|
|
343
|
+
buildRequest() {
|
|
344
|
+
return this.serializer.toRequest(this.form(), this.mapperRegistry());
|
|
303
345
|
}
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
return;
|
|
307
|
-
this.addReactiveLogic(this.mainHandler().getReactiveLogic(this.form()));
|
|
308
|
-
this._allHandlersLoaded.set(true);
|
|
346
|
+
ngOnDestroy() {
|
|
347
|
+
this._logicSubscription.unsubscribe();
|
|
309
348
|
}
|
|
310
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.21", ngImport: i0, type:
|
|
311
|
-
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 });
|
|
312
351
|
}
|
|
313
|
-
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: [{
|
|
314
353
|
type: Directive
|
|
315
|
-
}] });
|
|
354
|
+
}], ctorParameters: () => [{ type: FormHydrator }, { type: FormSerializer }] });
|
|
316
355
|
|
|
317
356
|
/*
|
|
318
357
|
* Public API Surface of core
|
|
@@ -322,5 +361,5 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.21", ngImpo
|
|
|
322
361
|
* Generated bundle index. Do not edit.
|
|
323
362
|
*/
|
|
324
363
|
|
|
325
|
-
export { FormControlBase,
|
|
364
|
+
export { FormControlBase, FormHandlerBase, FormHydrator, FormMapperBase, FormOrchestrator, FormSerializer, formatNumber, getControl, getControlValue, parseNumber };
|
|
326
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-value-assessor.ts","../../../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 {\r\n Directive,\r\n ElementRef,\r\n HostBinding,\r\n Optional,\r\n Self,\r\n inject,\r\n ChangeDetectorRef,\r\n input,\r\n} from '@angular/core';\r\nimport { ControlValueAccessor, NgControl } from '@angular/forms';\r\n\r\n/**\r\n * Base implementation for custom form controls that integrate with Angular Reactive Forms (ControlValueAccessor)\r\n *\r\n * NOTE: This class is UI-layer only and should not be used in form orchestration logic.\r\n */\r\n\r\n@Directive()\r\nexport abstract class FormControlValueAccessor<\r\n T,\r\n> implements ControlValueAccessor {\r\n protected readonly cdr = inject(ChangeDetectorRef);\r\n\r\n readonly _name = input<string>('', { alias: 'name' });\r\n readonly _placeholder = input<string>('', { alias: 'placeholder' });\r\n readonly _required = input<boolean>(false, { alias: 'required' });\r\n readonly _disabled = input<boolean>(false, { alias: 'disabled' });\r\n readonly _readonly = input<boolean>(false, { alias: 'readonly' });\r\n\r\n readonly formControlName = input<string>('');\r\n\r\n get name(): string {\r\n return this._name();\r\n }\r\n\r\n get placeholder(): string {\r\n return this._placeholder();\r\n }\r\n\r\n get required(): boolean {\r\n return this._required();\r\n }\r\n\r\n get disabled(): boolean {\r\n return this._disabled();\r\n }\r\n\r\n get readonly(): boolean {\r\n return this._readonly();\r\n }\r\n\r\n static nextId = 0;\r\n\r\n @HostBinding()\r\n id = `nmf-form-control-${FormControlValueAccessor.nextId++}`;\r\n\r\n _value: T | null = null;\r\n\r\n get value(): T | null {\r\n return this._value;\r\n }\r\n\r\n set value(val: T | null) {\r\n this._value = val;\r\n }\r\n\r\n onChange = (_value: T) => {};\r\n onTouched = () => {};\r\n\r\n constructor(\r\n @Optional() @Self() public ngControl: NgControl,\r\n protected elementRef: ElementRef<HTMLElement>,\r\n ) {\r\n if (this.ngControl != null) {\r\n this.ngControl.valueAccessor = this;\r\n }\r\n }\r\n\r\n writeValue(value: T): void {\r\n this._value = value;\r\n this.cdr.markForCheck();\r\n }\r\n\r\n registerOnChange(fn: (value: T) => void): void {\r\n this.onChange = fn;\r\n }\r\n\r\n registerOnTouched(fn: () => void): void {\r\n this.onTouched = fn;\r\n }\r\n}\r\n","import {\r\n FormControl,\r\n FormGroup,\r\n FormGroupDirective,\r\n Validators,\r\n} from '@angular/forms';\r\nimport {\r\n computed,\r\n Directive,\r\n inject,\r\n input,\r\n OnInit,\r\n signal,\r\n} from '@angular/core';\r\nimport { takeUntilDestroyed } from '@angular/core/rxjs-interop';\r\nimport { FormControlValueAccessor } from './form-control-value-assessor';\r\n\r\n@Directive()\r\nexport abstract class FormControlBase<T>\r\n extends FormControlValueAccessor<T>\r\n implements OnInit\r\n{\r\n readonly label = input<string>('');\r\n readonly classList = input<string[]>([]);\r\n readonly loading = input<boolean>(false);\r\n\r\n protected _form = signal<FormGroup>(new FormGroup({}));\r\n protected _controlName = signal<string>('');\r\n\r\n readonly form = this._form.asReadonly();\r\n readonly controlName = this._controlName.asReadonly();\r\n\r\n readonly control = computed(\r\n () => this._form().get(this._controlName()) as FormControl,\r\n );\r\n\r\n private parentFormGroup = inject(FormGroupDirective, {\r\n optional: true,\r\n host: true,\r\n });\r\n\r\n ngOnInit() {\r\n const controlName = this.formControlName() ?? 'default';\r\n const form = this.parentFormGroup?.form;\r\n\r\n if (!form) {\r\n throw new Error(\r\n `FormGroupDirective not found. Ensure component is used inside a form group`,\r\n );\r\n }\r\n\r\n this._form.set(form);\r\n this._controlName.set(controlName);\r\n\r\n const control = form.get(controlName);\r\n\r\n if (!control) {\r\n throw new Error(\r\n `FormControl '${controlName}' not found in parent FormGroup`,\r\n );\r\n }\r\n\r\n control.statusChanges\r\n .pipe(takeUntilDestroyed())\r\n .subscribe(() => this.cdr.markForCheck());\r\n }\r\n\r\n protected isRequired(): boolean {\r\n const control = this._form()?.get(this._controlName());\r\n return !!control && control.hasValidator(Validators.required);\r\n }\r\n\r\n protected serverError = computed(\r\n () => this.form()?.errors?.['server'] as string | undefined,\r\n );\r\n\r\n protected getErrorMessage(): string {\r\n const control = this._form()?.get(this._controlName());\r\n\r\n if (!control || !control.errors || !control.touched) return '';\r\n\r\n const firstKey = Object.keys(control.errors)[0];\r\n const error = control.errors[firstKey];\r\n\r\n switch (firstKey) {\r\n case 'required':\r\n return 'This field is required';\r\n case 'minlength':\r\n return `Minimum length is ${error.requiredLength}`;\r\n case 'maxlength':\r\n return `Maximum length is ${error.requiredLength}`;\r\n case 'min':\r\n return `Minimum value is ${error.min}`;\r\n case 'max':\r\n return `Maximum value is ${error.max}`;\r\n case 'email':\r\n return 'Invalid email address';\r\n case 'pattern':\r\n return 'Invalid format';\r\n case 'server':\r\n return error;\r\n default:\r\n return 'Invalid value';\r\n }\r\n }\r\n}\r\n","import { FormControl, FormGroup } from '@angular/forms';\r\n\r\nexport function getControl<T = unknown>(controlName: string, form: FormGroup) {\r\n if (!form) {\r\n throw new Error(\r\n `Missing form instance while getting the control of \"${controlName}\"`,\r\n );\r\n }\r\n\r\n const control = form.get(controlName) as FormControl<T>;\r\n if (!control) {\r\n throw new Error(`Missing control \"${controlName}\" in form \"${form}\"`);\r\n }\r\n\r\n return control;\r\n}\r\n\r\nexport function getControlValue<T = unknown>(\r\n controlName: string,\r\n form: FormGroup,\r\n): T | null;\r\n\r\nexport function getControlValue(\r\n controlName: string,\r\n form: FormGroup,\r\n): number | null;\r\n\r\nexport function getControlValue<T = unknown>(\r\n controlName: string,\r\n form: FormGroup,\r\n): T | null {\r\n const control = getControl<T>(controlName, form);\r\n if (!control) {\r\n throw new Error(`Missing control \"${controlName}\" in form \"${form}\"`);\r\n }\r\n\r\n const value = control.getRawValue();\r\n if (value === '') {\r\n return null;\r\n }\r\n\r\n if (typeof value === 'string') {\r\n const cleaned = value.replace(/,/g, '');\r\n\r\n if (!Number.isNaN(Number(cleaned))) {\r\n return parseCurrency(value) as T;\r\n }\r\n }\r\n\r\n return value;\r\n}\r\n\r\nexport function parseCurrency(\r\n currencyString: string | number | null | undefined,\r\n): number {\r\n if (currencyString == null) {\r\n return 0;\r\n }\r\n\r\n if (typeof currencyString === 'number') {\r\n return currencyString;\r\n }\r\n\r\n return Number(currencyString.replace(/[^0-9.-]/g, ''));\r\n}\r\n","import { FormControl, FormGroup } from '@angular/forms';\r\nimport { Observable, Subscription } from 'rxjs';\r\nimport { getControl } from './form.util';\r\n\r\nexport abstract class FormHandlerBase<ControlNames extends string = string> {\r\n abstract getReactiveLogic(form?: FormGroup): Subscription;\r\n\r\n protected registeredControls: Record<string, FormControl> = {};\r\n\r\n /**\r\n * Registers form controls for later reactive access.\r\n */\r\n registerControls(form: FormGroup, controlNames: ControlNames[]): void {\r\n controlNames.forEach((cn) => {\r\n const control = getControl(cn.replace(/_/g, '.'), form);\r\n\r\n if (!control) {\r\n throw new Error(\r\n `Failed to register control with name: \"${cn}\" in form group: \"${form}\"`,\r\n );\r\n }\r\n\r\n const key = cn as ControlNames;\r\n this.registeredControls[key] = control;\r\n });\r\n }\r\n\r\n valueChangesOf<T>(key: ControlNames): Observable<T> {\r\n if (!this.registeredControls[key]) {\r\n throw new Error(\r\n `Control with name: \"${key}\" not found. Ensure it is registered in registerControls(...)`,\r\n );\r\n }\r\n\r\n return this.registeredControls[key].valueChanges as Observable<T>;\r\n }\r\n}\r\n","import { FormGroup } from '@angular/forms';\r\n\r\nexport abstract class FormMapperBase<\r\n TModelIn = unknown,\r\n TModelOut = unknown,\r\n TFormModel = unknown,\r\n TStore = Record<string, unknown>,\r\n> {\r\n /**\r\n * Maps form state + external store into an API request payload.\r\n */\r\n abstract buildRequest(form: FormGroup, store: TStore): Partial<TModelOut>;\r\n\r\n /**\r\n * Transforms a domain/API model into a form-compatible structure.\r\n */\r\n abstract transformFromModel(model: TModelIn): TFormModel;\r\n\r\n patchForm(\r\n form: FormGroup,\r\n data: TFormModel,\r\n _context: TStore,\r\n emitEvent: boolean = false,\r\n ): void {\r\n form.patchValue(\r\n {\r\n ...(data as Record<string, unknown>),\r\n },\r\n { emitEvent },\r\n );\r\n }\r\n\r\n patchFromModel(form: FormGroup, model: TModelIn, store: TStore): void {\r\n const formModel = this.transformFromModel(model);\r\n this.patchForm(form, formModel, store);\r\n }\r\n}\r\n","import { FormGroup } from '@angular/forms';\r\nimport { Directive, OnDestroy, signal } from '@angular/core';\r\nimport { Subscription } from 'rxjs';\r\nimport { FormHandlerBase } from './form-handler-base';\r\n\r\nexport type FormStatus = 'idle' | 'submitting' | 'error' | 'success';\r\n\r\ntype FormHandlerRegistry = Record<string, FormHandlerBase<string>>;\r\n\r\ninterface FormOrchestratorOptions {\r\n mainHandler?: FormHandlerBase<string> | null;\r\n subHandlers?: FormHandlerRegistry;\r\n}\r\n\r\n@Directive()\r\nexport abstract class FormOrchestratorBase implements OnDestroy {\r\n private _form = signal<FormGroup>(new FormGroup({}));\r\n\r\n private _mainHandler = signal<FormHandlerBase<string> | null>(null);\r\n private _subHandlers = signal<FormHandlerRegistry>({});\r\n\r\n private _status = signal<FormStatus>('idle');\r\n private _errorMessage = signal<string | null>(null);\r\n\r\n private _loadedHandlers = signal<number>(0);\r\n private _allHandlersLoaded = signal<boolean>(false);\r\n\r\n private _logicSubscription = new Subscription();\r\n\r\n public readonly form = this._form.asReadonly();\r\n public readonly mainHandler = this._mainHandler.asReadonly();\r\n public readonly subHandlers = this._subHandlers.asReadonly();\r\n public readonly status = this._status.asReadonly();\r\n public readonly errorMessage = this._errorMessage.asReadonly();\r\n\r\n /**\r\n * Initializes orchestration state.\r\n * Must be called before any subform registration or handler execution.\r\n */\r\n public initialize(\r\n form: FormGroup,\r\n formOrchestratorOptions?: FormOrchestratorOptions,\r\n ) {\r\n const { mainHandler, subHandlers = {} } = formOrchestratorOptions ?? {};\r\n\r\n this._form.set(form);\r\n this._mainHandler.set(mainHandler ?? null);\r\n this._subHandlers.set(subHandlers);\r\n this._loadedHandlers.set(0);\r\n\r\n const subHandlerCount = Object.keys(this.subHandlers());\r\n if (subHandlerCount.length === 0) {\r\n this.loadMainHandler();\r\n }\r\n }\r\n\r\n public setForm(form: FormGroup) {\r\n this._form.set(form);\r\n }\r\n\r\n public getHandler(key: string): FormHandlerBase<string> | undefined {\r\n return this.subHandlers()[key];\r\n }\r\n\r\n public setHandler(key: string, handler: FormHandlerBase<string>) {\r\n this._subHandlers.set({\r\n ...this._subHandlers(),\r\n [key]: handler,\r\n });\r\n }\r\n\r\n public addReactiveLogic(subscription: Subscription) {\r\n this._logicSubscription.add(subscription);\r\n }\r\n\r\n public setStatus(status: FormStatus) {\r\n this._status.set(status);\r\n }\r\n\r\n public setErrorMessage(message: string | null) {\r\n this._errorMessage.set(message);\r\n }\r\n\r\n ngOnDestroy(): void {\r\n this._logicSubscription.unsubscribe();\r\n }\r\n\r\n /**\r\n * Registers a subform into the main form tree and coordinates handler execution.\r\n *\r\n * IMPORTANT:\r\n * - Handler execution is gated until all registered subhandlers are ready.\r\n * - Calling order matters; this is lifecycle-sensitive orchestration logic.\r\n */\r\n onSubformReady(\r\n subform: FormGroup,\r\n groupName: string,\r\n nestGroups: boolean = false,\r\n ): void {\r\n if (nestGroups) {\r\n this.form().setControl(groupName, subform);\r\n } else {\r\n const keys = Object.keys(subform.controls);\r\n keys.forEach((key) => {\r\n this.form().setControl(key, subform.get(key));\r\n });\r\n }\r\n\r\n // Prevent duplicate main handler execution when all subhandlers already resolved\r\n if (this._allHandlersLoaded()) {\r\n return;\r\n }\r\n\r\n const subformHandler = this.subHandlers()[groupName];\r\n\r\n if (subformHandler) {\r\n this._loadedHandlers.set(this._loadedHandlers() + 1);\r\n this.addReactiveLogic(subformHandler.getReactiveLogic());\r\n }\r\n\r\n const totalSubHandlers = Object.keys(this.subHandlers()).length;\r\n const allSubHandlersLoaded = this._loadedHandlers() === totalSubHandlers;\r\n\r\n if (allSubHandlersLoaded && this.mainHandler()) {\r\n this.loadMainHandler();\r\n }\r\n }\r\n\r\n private loadMainHandler() {\r\n if (!this.mainHandler()) return;\r\n\r\n this.addReactiveLogic(this.mainHandler()!.getReactiveLogic(this.form()));\r\n this._allHandlersLoaded.set(true);\r\n }\r\n}\r\n","/*\r\n * Public API Surface of core\r\n */\r\n\r\nexport * from './lib/form-control-value-assessor';\r\nexport * from './lib/form-control-base';\r\nexport * from './lib/form-handler-base';\r\nexport * from './lib/form-mapper-base';\r\nexport * from './lib/form-orchestrator-base';\r\nexport * from './lib/form.util';\r\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
|
+
}
|
|
@@ -2,4 +2,5 @@ import { FormControl, FormGroup } from '@angular/forms';
|
|
|
2
2
|
export declare function getControl<T = unknown>(controlName: string, form: FormGroup): FormControl<T>;
|
|
3
3
|
export declare function getControlValue<T = unknown>(controlName: string, form: FormGroup): T | null;
|
|
4
4
|
export declare function getControlValue(controlName: string, form: FormGroup): number | null;
|
|
5
|
-
export declare function
|
|
5
|
+
export declare function parseNumber(input: string | number | null | undefined): number | null;
|
|
6
|
+
export declare function formatNumber(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,6 +1,8 @@
|
|
|
1
|
-
export * from './lib/form-control-
|
|
2
|
-
export * from './lib/form-
|
|
3
|
-
export * from './lib/form-
|
|
4
|
-
export * from './lib/form-
|
|
5
|
-
export * from './lib/form-orchestrator
|
|
6
|
-
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,21 +0,0 @@
|
|
|
1
|
-
import { FormControl, FormGroup } from '@angular/forms';
|
|
2
|
-
import { OnInit } from '@angular/core';
|
|
3
|
-
import { FormControlValueAccessor } from './form-control-value-assessor';
|
|
4
|
-
import * as i0 from "@angular/core";
|
|
5
|
-
export declare abstract class FormControlBase<T> extends FormControlValueAccessor<T> implements OnInit {
|
|
6
|
-
readonly label: import("@angular/core").InputSignal<string>;
|
|
7
|
-
readonly classList: import("@angular/core").InputSignal<string[]>;
|
|
8
|
-
readonly loading: import("@angular/core").InputSignal<boolean>;
|
|
9
|
-
protected _form: import("@angular/core").WritableSignal<FormGroup<any>>;
|
|
10
|
-
protected _controlName: import("@angular/core").WritableSignal<string>;
|
|
11
|
-
readonly form: import("@angular/core").Signal<FormGroup<any>>;
|
|
12
|
-
readonly controlName: import("@angular/core").Signal<string>;
|
|
13
|
-
readonly control: import("@angular/core").Signal<FormControl<any>>;
|
|
14
|
-
private parentFormGroup;
|
|
15
|
-
ngOnInit(): void;
|
|
16
|
-
protected isRequired(): boolean;
|
|
17
|
-
protected serverError: import("@angular/core").Signal<string | undefined>;
|
|
18
|
-
protected getErrorMessage(): string;
|
|
19
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<FormControlBase<any>, never>;
|
|
20
|
-
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; }; }, {}, never, never, true, never>;
|
|
21
|
-
}
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
import { ElementRef, ChangeDetectorRef } from '@angular/core';
|
|
2
|
-
import { ControlValueAccessor, NgControl } from '@angular/forms';
|
|
3
|
-
import * as i0 from "@angular/core";
|
|
4
|
-
/**
|
|
5
|
-
* Base implementation for custom form controls that integrate with Angular Reactive Forms (ControlValueAccessor)
|
|
6
|
-
*
|
|
7
|
-
* NOTE: This class is UI-layer only and should not be used in form orchestration logic.
|
|
8
|
-
*/
|
|
9
|
-
export declare abstract class FormControlValueAccessor<T> implements ControlValueAccessor {
|
|
10
|
-
ngControl: NgControl;
|
|
11
|
-
protected elementRef: ElementRef<HTMLElement>;
|
|
12
|
-
protected readonly cdr: ChangeDetectorRef;
|
|
13
|
-
readonly _name: import("@angular/core").InputSignal<string>;
|
|
14
|
-
readonly _placeholder: import("@angular/core").InputSignal<string>;
|
|
15
|
-
readonly _required: import("@angular/core").InputSignal<boolean>;
|
|
16
|
-
readonly _disabled: import("@angular/core").InputSignal<boolean>;
|
|
17
|
-
readonly _readonly: import("@angular/core").InputSignal<boolean>;
|
|
18
|
-
readonly formControlName: import("@angular/core").InputSignal<string>;
|
|
19
|
-
get name(): string;
|
|
20
|
-
get placeholder(): string;
|
|
21
|
-
get required(): boolean;
|
|
22
|
-
get disabled(): boolean;
|
|
23
|
-
get readonly(): boolean;
|
|
24
|
-
static nextId: number;
|
|
25
|
-
id: string;
|
|
26
|
-
_value: T | null;
|
|
27
|
-
get value(): T | null;
|
|
28
|
-
set value(val: T | null);
|
|
29
|
-
onChange: (_value: T) => void;
|
|
30
|
-
onTouched: () => void;
|
|
31
|
-
constructor(ngControl: NgControl, elementRef: ElementRef<HTMLElement>);
|
|
32
|
-
writeValue(value: T): void;
|
|
33
|
-
registerOnChange(fn: (value: T) => void): void;
|
|
34
|
-
registerOnTouched(fn: () => void): void;
|
|
35
|
-
static ɵfac: i0.ɵɵFactoryDeclaration<FormControlValueAccessor<any>, [{ optional: true; self: true; }, null]>;
|
|
36
|
-
static ɵdir: i0.ɵɵDirectiveDeclaration<FormControlValueAccessor<any>, never, never, { "_name": { "alias": "name"; "required": false; "isSignal": true; }; "_placeholder": { "alias": "placeholder"; "required": false; "isSignal": true; }; "_required": { "alias": "required"; "required": false; "isSignal": true; }; "_disabled": { "alias": "disabled"; "required": false; "isSignal": true; }; "_readonly": { "alias": "readonly"; "required": false; "isSignal": true; }; "formControlName": { "alias": "formControlName"; "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 {};
|