@angular/forms 21.2.0-next.1 → 21.2.0-next.3
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/fesm2022/{_structure-chunk.mjs → _validation_errors-chunk.mjs} +138 -43
- package/fesm2022/_validation_errors-chunk.mjs.map +1 -0
- package/fesm2022/forms.mjs +170 -189
- package/fesm2022/forms.mjs.map +1 -1
- package/fesm2022/signals-compat.mjs +386 -47
- package/fesm2022/signals-compat.mjs.map +1 -1
- package/fesm2022/signals.mjs +683 -238
- package/fesm2022/signals.mjs.map +1 -1
- package/package.json +4 -4
- package/resources/code-examples.db +0 -0
- package/types/_structure-chunk.d.ts +642 -1406
- package/types/forms.d.ts +1 -1
- package/types/signals-compat.d.ts +131 -8
- package/types/signals.d.ts +107 -48
- package/fesm2022/_structure-chunk.mjs.map +0 -1
package/fesm2022/signals.mjs
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v21.2.0-next.
|
|
2
|
+
* @license Angular v21.2.0-next.3
|
|
3
3
|
* (c) 2010-2026 Google LLC. https://angular.dev/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
import * as i0 from '@angular/core';
|
|
8
|
-
import { InjectionToken,
|
|
9
|
-
import {
|
|
10
|
-
|
|
11
|
-
export { MetadataKey, MetadataReducer, apply, applyEach, applyWhen, applyWhenValue, form, schema, submit } from './_structure-chunk.mjs';
|
|
8
|
+
import { InjectionToken, ɵisPromise as _isPromise, resource, signal, linkedSignal, inject, ɵRuntimeError as _RuntimeError, untracked, input, Renderer2, DestroyRef, computed, Injector, ElementRef, afterRenderEffect, effect, Directive } from '@angular/core';
|
|
9
|
+
import { assertPathIsCurrent, FieldPathNode, addDefaultField, metadata, createMetadataKey, MAX, MAX_LENGTH, MIN, MIN_LENGTH, PATTERN, REQUIRED, createManagedMetadataKey, DEBOUNCER, signalErrorsToValidationErrors, submit } from './_validation_errors-chunk.mjs';
|
|
10
|
+
export { MetadataKey, MetadataReducer, apply, applyEach, applyWhen, applyWhenValue, form, schema } from './_validation_errors-chunk.mjs';
|
|
12
11
|
import { httpResource } from '@angular/common/http';
|
|
12
|
+
import { Validators, NG_VALUE_ACCESSOR, NgControl } from '@angular/forms';
|
|
13
13
|
import '@angular/core/primitives/signals';
|
|
14
14
|
|
|
15
15
|
const SIGNAL_FORMS_CONFIG = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'SIGNAL_FORMS_CONFIG' : '');
|
|
@@ -21,212 +21,6 @@ function provideSignalFormsConfig(config) {
|
|
|
21
21
|
}];
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
class InteropNgControl {
|
|
25
|
-
field;
|
|
26
|
-
constructor(field) {
|
|
27
|
-
this.field = field;
|
|
28
|
-
}
|
|
29
|
-
control = this;
|
|
30
|
-
get value() {
|
|
31
|
-
return this.field().value();
|
|
32
|
-
}
|
|
33
|
-
get valid() {
|
|
34
|
-
return this.field().valid();
|
|
35
|
-
}
|
|
36
|
-
get invalid() {
|
|
37
|
-
return this.field().invalid();
|
|
38
|
-
}
|
|
39
|
-
get pending() {
|
|
40
|
-
return this.field().pending();
|
|
41
|
-
}
|
|
42
|
-
get disabled() {
|
|
43
|
-
return this.field().disabled();
|
|
44
|
-
}
|
|
45
|
-
get enabled() {
|
|
46
|
-
return !this.field().disabled();
|
|
47
|
-
}
|
|
48
|
-
get errors() {
|
|
49
|
-
const errors = this.field().errors();
|
|
50
|
-
if (errors.length === 0) {
|
|
51
|
-
return null;
|
|
52
|
-
}
|
|
53
|
-
const errObj = {};
|
|
54
|
-
for (const error of errors) {
|
|
55
|
-
errObj[error.kind] = error;
|
|
56
|
-
}
|
|
57
|
-
return errObj;
|
|
58
|
-
}
|
|
59
|
-
get pristine() {
|
|
60
|
-
return !this.field().dirty();
|
|
61
|
-
}
|
|
62
|
-
get dirty() {
|
|
63
|
-
return this.field().dirty();
|
|
64
|
-
}
|
|
65
|
-
get touched() {
|
|
66
|
-
return this.field().touched();
|
|
67
|
-
}
|
|
68
|
-
get untouched() {
|
|
69
|
-
return !this.field().touched();
|
|
70
|
-
}
|
|
71
|
-
get status() {
|
|
72
|
-
if (this.field().disabled()) {
|
|
73
|
-
return 'DISABLED';
|
|
74
|
-
}
|
|
75
|
-
if (this.field().valid()) {
|
|
76
|
-
return 'VALID';
|
|
77
|
-
}
|
|
78
|
-
if (this.field().invalid()) {
|
|
79
|
-
return 'INVALID';
|
|
80
|
-
}
|
|
81
|
-
if (this.field().pending()) {
|
|
82
|
-
return 'PENDING';
|
|
83
|
-
}
|
|
84
|
-
throw new _RuntimeError(1910, ngDevMode && 'Unknown form control status');
|
|
85
|
-
}
|
|
86
|
-
valueAccessor = null;
|
|
87
|
-
hasValidator(validator) {
|
|
88
|
-
if (validator === Validators.required) {
|
|
89
|
-
return this.field().required();
|
|
90
|
-
}
|
|
91
|
-
return false;
|
|
92
|
-
}
|
|
93
|
-
updateValueAndValidity() {}
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
const FORM_FIELD = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'FORM_FIELD' : '');
|
|
97
|
-
const controlInstructions = {
|
|
98
|
-
create: __controlCreate,
|
|
99
|
-
update: _controlUpdate
|
|
100
|
-
};
|
|
101
|
-
class FormField {
|
|
102
|
-
element = inject(ElementRef).nativeElement;
|
|
103
|
-
injector = inject(Injector);
|
|
104
|
-
fieldTree = input.required({
|
|
105
|
-
...(ngDevMode ? {
|
|
106
|
-
debugName: "fieldTree"
|
|
107
|
-
} : {}),
|
|
108
|
-
alias: 'formField'
|
|
109
|
-
});
|
|
110
|
-
state = computed(() => this.fieldTree()(), ...(ngDevMode ? [{
|
|
111
|
-
debugName: "state"
|
|
112
|
-
}] : []));
|
|
113
|
-
bindingOptions = signal(undefined, ...(ngDevMode ? [{
|
|
114
|
-
debugName: "bindingOptions"
|
|
115
|
-
}] : []));
|
|
116
|
-
parseErrors = computed(() => this.bindingOptions()?.parseErrors?.().map(err => ({
|
|
117
|
-
...err,
|
|
118
|
-
fieldTree: this.fieldTree(),
|
|
119
|
-
formField: this
|
|
120
|
-
})) ?? [], ...(ngDevMode ? [{
|
|
121
|
-
debugName: "parseErrors"
|
|
122
|
-
}] : []));
|
|
123
|
-
errors = computed(() => this.state().errors().filter(err => !err.formField || err.formField === this), ...(ngDevMode ? [{
|
|
124
|
-
debugName: "errors"
|
|
125
|
-
}] : []));
|
|
126
|
-
[_CONTROL] = controlInstructions;
|
|
127
|
-
config = inject(SIGNAL_FORMS_CONFIG, {
|
|
128
|
-
optional: true
|
|
129
|
-
});
|
|
130
|
-
classes = Object.entries(this.config?.classes ?? {}).map(([className, computation]) => [className, computed(() => computation(this))]);
|
|
131
|
-
controlValueAccessors = inject(NG_VALUE_ACCESSOR, {
|
|
132
|
-
optional: true,
|
|
133
|
-
self: true
|
|
134
|
-
});
|
|
135
|
-
interopNgControl;
|
|
136
|
-
get ɵinteropControl() {
|
|
137
|
-
return this.controlValueAccessors?.[0] ?? this.interopNgControl?.valueAccessor ?? undefined;
|
|
138
|
-
}
|
|
139
|
-
getOrCreateNgControl() {
|
|
140
|
-
return this.interopNgControl ??= new InteropNgControl(this.state);
|
|
141
|
-
}
|
|
142
|
-
registerAsBinding(bindingOptions) {
|
|
143
|
-
if (untracked(this.bindingOptions)) {
|
|
144
|
-
throw new _RuntimeError(1913, ngDevMode && 'FormField already registered as a binding');
|
|
145
|
-
}
|
|
146
|
-
this.bindingOptions.set(bindingOptions);
|
|
147
|
-
effect(onCleanup => {
|
|
148
|
-
const fieldNode = this.state();
|
|
149
|
-
fieldNode.nodeState.formFieldBindings.update(controls => [...controls, this]);
|
|
150
|
-
onCleanup(() => {
|
|
151
|
-
fieldNode.nodeState.formFieldBindings.update(controls => controls.filter(c => c !== this));
|
|
152
|
-
});
|
|
153
|
-
}, {
|
|
154
|
-
injector: this.injector
|
|
155
|
-
});
|
|
156
|
-
}
|
|
157
|
-
focus(options) {
|
|
158
|
-
const bindingOptions = untracked(this.bindingOptions);
|
|
159
|
-
if (bindingOptions?.focus) {
|
|
160
|
-
bindingOptions.focus(options);
|
|
161
|
-
} else {
|
|
162
|
-
this.element.focus(options);
|
|
163
|
-
}
|
|
164
|
-
}
|
|
165
|
-
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
166
|
-
minVersion: "12.0.0",
|
|
167
|
-
version: "21.2.0-next.1",
|
|
168
|
-
ngImport: i0,
|
|
169
|
-
type: FormField,
|
|
170
|
-
deps: [],
|
|
171
|
-
target: i0.ɵɵFactoryTarget.Directive
|
|
172
|
-
});
|
|
173
|
-
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
174
|
-
minVersion: "17.1.0",
|
|
175
|
-
version: "21.2.0-next.1",
|
|
176
|
-
type: FormField,
|
|
177
|
-
isStandalone: true,
|
|
178
|
-
selector: "[formField]",
|
|
179
|
-
inputs: {
|
|
180
|
-
fieldTree: {
|
|
181
|
-
classPropertyName: "fieldTree",
|
|
182
|
-
publicName: "formField",
|
|
183
|
-
isSignal: true,
|
|
184
|
-
isRequired: true,
|
|
185
|
-
transformFunction: null
|
|
186
|
-
}
|
|
187
|
-
},
|
|
188
|
-
providers: [{
|
|
189
|
-
provide: FORM_FIELD,
|
|
190
|
-
useExisting: FormField
|
|
191
|
-
}, {
|
|
192
|
-
provide: NgControl,
|
|
193
|
-
useFactory: () => inject(FormField).getOrCreateNgControl()
|
|
194
|
-
}],
|
|
195
|
-
exportAs: ["formField"],
|
|
196
|
-
ngImport: i0
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
i0.ɵɵngDeclareClassMetadata({
|
|
200
|
-
minVersion: "12.0.0",
|
|
201
|
-
version: "21.2.0-next.1",
|
|
202
|
-
ngImport: i0,
|
|
203
|
-
type: FormField,
|
|
204
|
-
decorators: [{
|
|
205
|
-
type: Directive,
|
|
206
|
-
args: [{
|
|
207
|
-
selector: '[formField]',
|
|
208
|
-
exportAs: 'formField',
|
|
209
|
-
providers: [{
|
|
210
|
-
provide: FORM_FIELD,
|
|
211
|
-
useExisting: FormField
|
|
212
|
-
}, {
|
|
213
|
-
provide: NgControl,
|
|
214
|
-
useFactory: () => inject(FormField).getOrCreateNgControl()
|
|
215
|
-
}]
|
|
216
|
-
}]
|
|
217
|
-
}],
|
|
218
|
-
propDecorators: {
|
|
219
|
-
fieldTree: [{
|
|
220
|
-
type: i0.Input,
|
|
221
|
-
args: [{
|
|
222
|
-
isSignal: true,
|
|
223
|
-
alias: "formField",
|
|
224
|
-
required: true
|
|
225
|
-
}]
|
|
226
|
-
}]
|
|
227
|
-
}
|
|
228
|
-
});
|
|
229
|
-
|
|
230
24
|
function disabled(path, logic) {
|
|
231
25
|
assertPathIsCurrent(path);
|
|
232
26
|
const pathNode = FieldPathNode.unwrapFieldPath(path);
|
|
@@ -304,10 +98,7 @@ function patternError(pattern, options) {
|
|
|
304
98
|
function emailError(options) {
|
|
305
99
|
return new EmailValidationError(options);
|
|
306
100
|
}
|
|
307
|
-
|
|
308
|
-
return new StandardSchemaValidationError(issue, options);
|
|
309
|
-
}
|
|
310
|
-
class _NgValidationError {
|
|
101
|
+
class BaseNgValidationError {
|
|
311
102
|
__brand = undefined;
|
|
312
103
|
kind = '';
|
|
313
104
|
fieldTree;
|
|
@@ -318,10 +109,10 @@ class _NgValidationError {
|
|
|
318
109
|
}
|
|
319
110
|
}
|
|
320
111
|
}
|
|
321
|
-
class RequiredValidationError extends
|
|
112
|
+
class RequiredValidationError extends BaseNgValidationError {
|
|
322
113
|
kind = 'required';
|
|
323
114
|
}
|
|
324
|
-
class MinValidationError extends
|
|
115
|
+
class MinValidationError extends BaseNgValidationError {
|
|
325
116
|
min;
|
|
326
117
|
kind = 'min';
|
|
327
118
|
constructor(min, options) {
|
|
@@ -329,7 +120,7 @@ class MinValidationError extends _NgValidationError {
|
|
|
329
120
|
this.min = min;
|
|
330
121
|
}
|
|
331
122
|
}
|
|
332
|
-
class MaxValidationError extends
|
|
123
|
+
class MaxValidationError extends BaseNgValidationError {
|
|
333
124
|
max;
|
|
334
125
|
kind = 'max';
|
|
335
126
|
constructor(max, options) {
|
|
@@ -337,7 +128,7 @@ class MaxValidationError extends _NgValidationError {
|
|
|
337
128
|
this.max = max;
|
|
338
129
|
}
|
|
339
130
|
}
|
|
340
|
-
class MinLengthValidationError extends
|
|
131
|
+
class MinLengthValidationError extends BaseNgValidationError {
|
|
341
132
|
minLength;
|
|
342
133
|
kind = 'minLength';
|
|
343
134
|
constructor(minLength, options) {
|
|
@@ -345,7 +136,7 @@ class MinLengthValidationError extends _NgValidationError {
|
|
|
345
136
|
this.minLength = minLength;
|
|
346
137
|
}
|
|
347
138
|
}
|
|
348
|
-
class MaxLengthValidationError extends
|
|
139
|
+
class MaxLengthValidationError extends BaseNgValidationError {
|
|
349
140
|
maxLength;
|
|
350
141
|
kind = 'maxLength';
|
|
351
142
|
constructor(maxLength, options) {
|
|
@@ -353,7 +144,7 @@ class MaxLengthValidationError extends _NgValidationError {
|
|
|
353
144
|
this.maxLength = maxLength;
|
|
354
145
|
}
|
|
355
146
|
}
|
|
356
|
-
class PatternValidationError extends
|
|
147
|
+
class PatternValidationError extends BaseNgValidationError {
|
|
357
148
|
pattern;
|
|
358
149
|
kind = 'pattern';
|
|
359
150
|
constructor(pattern, options) {
|
|
@@ -361,18 +152,10 @@ class PatternValidationError extends _NgValidationError {
|
|
|
361
152
|
this.pattern = pattern;
|
|
362
153
|
}
|
|
363
154
|
}
|
|
364
|
-
class EmailValidationError extends
|
|
155
|
+
class EmailValidationError extends BaseNgValidationError {
|
|
365
156
|
kind = 'email';
|
|
366
157
|
}
|
|
367
|
-
|
|
368
|
-
issue;
|
|
369
|
-
kind = 'standardSchema';
|
|
370
|
-
constructor(issue, options) {
|
|
371
|
-
super(options);
|
|
372
|
-
this.issue = issue;
|
|
373
|
-
}
|
|
374
|
-
}
|
|
375
|
-
const NgValidationError = _NgValidationError;
|
|
158
|
+
const NgValidationError = BaseNgValidationError;
|
|
376
159
|
|
|
377
160
|
const EMAIL_REGEXP = /^(?=.{1,254}$)(?=.{1,64}@)[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-zA-Z0-9!#$%&'*+/=?^_`{|}~-]+)*@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
378
161
|
function email(path, config) {
|
|
@@ -588,17 +371,16 @@ function validateTree(path, logic) {
|
|
|
588
371
|
}
|
|
589
372
|
|
|
590
373
|
function validateStandardSchema(path, schema) {
|
|
591
|
-
const VALIDATOR_MEMO = metadata(path, createMetadataKey(),
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
return schema['~standard'].validate(value());
|
|
374
|
+
const VALIDATOR_MEMO = metadata(path, createMetadataKey(), ctx => {
|
|
375
|
+
const resolvedSchema = typeof schema === 'function' ? schema(ctx) : schema;
|
|
376
|
+
return resolvedSchema ? resolvedSchema['~standard'].validate(ctx.value()) : undefined;
|
|
595
377
|
});
|
|
596
378
|
validateTree(path, ({
|
|
597
379
|
state,
|
|
598
380
|
fieldTreeOf
|
|
599
381
|
}) => {
|
|
600
382
|
const result = state.metadata(VALIDATOR_MEMO)();
|
|
601
|
-
if (_isPromise(result)) {
|
|
383
|
+
if (!result || _isPromise(result)) {
|
|
602
384
|
return [];
|
|
603
385
|
}
|
|
604
386
|
return result?.issues?.map(issue => standardIssueToFormTreeError(fieldTreeOf(path), issue)) ?? [];
|
|
@@ -608,7 +390,7 @@ function validateStandardSchema(path, schema) {
|
|
|
608
390
|
state
|
|
609
391
|
}) => {
|
|
610
392
|
const result = state.metadata(VALIDATOR_MEMO)();
|
|
611
|
-
return _isPromise(result) ? result : undefined;
|
|
393
|
+
return result && _isPromise(result) ? result : undefined;
|
|
612
394
|
},
|
|
613
395
|
factory: params => {
|
|
614
396
|
return resource({
|
|
@@ -626,6 +408,9 @@ function validateStandardSchema(path, schema) {
|
|
|
626
408
|
onError: () => {}
|
|
627
409
|
});
|
|
628
410
|
}
|
|
411
|
+
function standardSchemaError(issue, options) {
|
|
412
|
+
return new StandardSchemaValidationError(issue, options);
|
|
413
|
+
}
|
|
629
414
|
function standardIssueToFormTreeError(fieldTree, issue) {
|
|
630
415
|
let target = fieldTree;
|
|
631
416
|
for (const pathPart of issue.path ?? []) {
|
|
@@ -636,6 +421,14 @@ function standardIssueToFormTreeError(fieldTree, issue) {
|
|
|
636
421
|
message: issue.message
|
|
637
422
|
}), target);
|
|
638
423
|
}
|
|
424
|
+
class StandardSchemaValidationError extends BaseNgValidationError {
|
|
425
|
+
issue;
|
|
426
|
+
kind = 'standardSchema';
|
|
427
|
+
constructor(issue, options) {
|
|
428
|
+
super(options);
|
|
429
|
+
this.issue = issue;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
639
432
|
|
|
640
433
|
function validateHttp(path, opts) {
|
|
641
434
|
validateAsync(path, {
|
|
@@ -658,6 +451,7 @@ function debounceForDuration(durationInMilliseconds) {
|
|
|
658
451
|
let timeoutId;
|
|
659
452
|
const onAbort = () => {
|
|
660
453
|
clearTimeout(timeoutId);
|
|
454
|
+
resolve();
|
|
661
455
|
};
|
|
662
456
|
timeoutId = setTimeout(() => {
|
|
663
457
|
abortSignal.removeEventListener('abort', onAbort);
|
|
@@ -671,5 +465,656 @@ function debounceForDuration(durationInMilliseconds) {
|
|
|
671
465
|
}
|
|
672
466
|
function immediate() {}
|
|
673
467
|
|
|
674
|
-
|
|
468
|
+
const FORM_FIELD_PARSE_ERRORS = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'FORM_FIELD_PARSE_ERRORS' : '');
|
|
469
|
+
|
|
470
|
+
function transformedValue(value, options) {
|
|
471
|
+
const {
|
|
472
|
+
parse,
|
|
473
|
+
format
|
|
474
|
+
} = options;
|
|
475
|
+
const parseErrors = signal([], ...(ngDevMode ? [{
|
|
476
|
+
debugName: "parseErrors"
|
|
477
|
+
}] : []));
|
|
478
|
+
const rawValue = linkedSignal(() => format(value()), ...(ngDevMode ? [{
|
|
479
|
+
debugName: "rawValue"
|
|
480
|
+
}] : []));
|
|
481
|
+
const formFieldParseErrors = inject(FORM_FIELD_PARSE_ERRORS, {
|
|
482
|
+
self: true,
|
|
483
|
+
optional: true
|
|
484
|
+
});
|
|
485
|
+
if (formFieldParseErrors) {
|
|
486
|
+
formFieldParseErrors.set(parseErrors);
|
|
487
|
+
}
|
|
488
|
+
const result = rawValue;
|
|
489
|
+
const originalSet = result.set.bind(result);
|
|
490
|
+
result.set = newRawValue => {
|
|
491
|
+
const result = parse(newRawValue);
|
|
492
|
+
parseErrors.set(result.errors ?? []);
|
|
493
|
+
if (result.value !== undefined) {
|
|
494
|
+
value.set(result.value);
|
|
495
|
+
}
|
|
496
|
+
originalSet(newRawValue);
|
|
497
|
+
};
|
|
498
|
+
result.update = updateFn => {
|
|
499
|
+
result.set(updateFn(rawValue()));
|
|
500
|
+
};
|
|
501
|
+
result.parseErrors = parseErrors.asReadonly();
|
|
502
|
+
return result;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
class InteropNgControl {
|
|
506
|
+
field;
|
|
507
|
+
constructor(field) {
|
|
508
|
+
this.field = field;
|
|
509
|
+
}
|
|
510
|
+
control = this;
|
|
511
|
+
get value() {
|
|
512
|
+
return this.field().value();
|
|
513
|
+
}
|
|
514
|
+
get valid() {
|
|
515
|
+
return this.field().valid();
|
|
516
|
+
}
|
|
517
|
+
get invalid() {
|
|
518
|
+
return this.field().invalid();
|
|
519
|
+
}
|
|
520
|
+
get pending() {
|
|
521
|
+
return this.field().pending();
|
|
522
|
+
}
|
|
523
|
+
get disabled() {
|
|
524
|
+
return this.field().disabled();
|
|
525
|
+
}
|
|
526
|
+
get enabled() {
|
|
527
|
+
return !this.field().disabled();
|
|
528
|
+
}
|
|
529
|
+
get errors() {
|
|
530
|
+
return signalErrorsToValidationErrors(this.field().errors());
|
|
531
|
+
}
|
|
532
|
+
get pristine() {
|
|
533
|
+
return !this.field().dirty();
|
|
534
|
+
}
|
|
535
|
+
get dirty() {
|
|
536
|
+
return this.field().dirty();
|
|
537
|
+
}
|
|
538
|
+
get touched() {
|
|
539
|
+
return this.field().touched();
|
|
540
|
+
}
|
|
541
|
+
get untouched() {
|
|
542
|
+
return !this.field().touched();
|
|
543
|
+
}
|
|
544
|
+
get status() {
|
|
545
|
+
if (this.field().disabled()) {
|
|
546
|
+
return 'DISABLED';
|
|
547
|
+
}
|
|
548
|
+
if (this.field().valid()) {
|
|
549
|
+
return 'VALID';
|
|
550
|
+
}
|
|
551
|
+
if (this.field().invalid()) {
|
|
552
|
+
return 'INVALID';
|
|
553
|
+
}
|
|
554
|
+
if (this.field().pending()) {
|
|
555
|
+
return 'PENDING';
|
|
556
|
+
}
|
|
557
|
+
throw new _RuntimeError(1910, ngDevMode && 'Unknown form control status');
|
|
558
|
+
}
|
|
559
|
+
valueAccessor = null;
|
|
560
|
+
hasValidator(validator) {
|
|
561
|
+
if (validator === Validators.required) {
|
|
562
|
+
return this.field().required();
|
|
563
|
+
}
|
|
564
|
+
return false;
|
|
565
|
+
}
|
|
566
|
+
updateValueAndValidity() {}
|
|
567
|
+
}
|
|
568
|
+
|
|
569
|
+
const FIELD_STATE_KEY_TO_CONTROL_BINDING = {
|
|
570
|
+
disabled: 'disabled',
|
|
571
|
+
disabledReasons: 'disabledReasons',
|
|
572
|
+
dirty: 'dirty',
|
|
573
|
+
errors: 'errors',
|
|
574
|
+
hidden: 'hidden',
|
|
575
|
+
invalid: 'invalid',
|
|
576
|
+
max: 'max',
|
|
577
|
+
maxLength: 'maxLength',
|
|
578
|
+
min: 'min',
|
|
579
|
+
minLength: 'minLength',
|
|
580
|
+
name: 'name',
|
|
581
|
+
pattern: 'pattern',
|
|
582
|
+
pending: 'pending',
|
|
583
|
+
readonly: 'readonly',
|
|
584
|
+
required: 'required',
|
|
585
|
+
touched: 'touched'
|
|
586
|
+
};
|
|
587
|
+
const CONTROL_BINDING_TO_FIELD_STATE_KEY = /* @__PURE__ */(() => {
|
|
588
|
+
const map = {};
|
|
589
|
+
for (const key of Object.keys(FIELD_STATE_KEY_TO_CONTROL_BINDING)) {
|
|
590
|
+
map[FIELD_STATE_KEY_TO_CONTROL_BINDING[key]] = key;
|
|
591
|
+
}
|
|
592
|
+
return map;
|
|
593
|
+
})();
|
|
594
|
+
function readFieldStateBindingValue(fieldState, key) {
|
|
595
|
+
const property = CONTROL_BINDING_TO_FIELD_STATE_KEY[key];
|
|
596
|
+
return fieldState[property]?.();
|
|
597
|
+
}
|
|
598
|
+
const CONTROL_BINDING_NAMES = /* @__PURE__ */(() => Object.values(FIELD_STATE_KEY_TO_CONTROL_BINDING))();
|
|
599
|
+
function createBindings() {
|
|
600
|
+
return {};
|
|
601
|
+
}
|
|
602
|
+
function bindingUpdated(bindings, key, value) {
|
|
603
|
+
if (bindings[key] !== value) {
|
|
604
|
+
bindings[key] = value;
|
|
605
|
+
return true;
|
|
606
|
+
}
|
|
607
|
+
return false;
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
function isNativeFormElement(element) {
|
|
611
|
+
return element.tagName === 'INPUT' || element.tagName === 'SELECT' || element.tagName === 'TEXTAREA';
|
|
612
|
+
}
|
|
613
|
+
function isNumericFormElement(element) {
|
|
614
|
+
if (element.tagName !== 'INPUT') {
|
|
615
|
+
return false;
|
|
616
|
+
}
|
|
617
|
+
const type = element.type;
|
|
618
|
+
return type === 'date' || type === 'datetime-local' || type === 'month' || type === 'number' || type === 'range' || type === 'time' || type === 'week';
|
|
619
|
+
}
|
|
620
|
+
function isTextualFormElement(element) {
|
|
621
|
+
return element.tagName === 'INPUT' || element.tagName === 'TEXTAREA';
|
|
622
|
+
}
|
|
623
|
+
function getNativeControlValue(element, currentValue) {
|
|
624
|
+
switch (element.type) {
|
|
625
|
+
case 'checkbox':
|
|
626
|
+
return element.checked;
|
|
627
|
+
case 'number':
|
|
628
|
+
case 'range':
|
|
629
|
+
case 'datetime-local':
|
|
630
|
+
if (typeof untracked(currentValue) === 'number') {
|
|
631
|
+
return element.valueAsNumber;
|
|
632
|
+
}
|
|
633
|
+
break;
|
|
634
|
+
case 'date':
|
|
635
|
+
case 'month':
|
|
636
|
+
case 'time':
|
|
637
|
+
case 'week':
|
|
638
|
+
const value = untracked(currentValue);
|
|
639
|
+
if (value === null || value instanceof Date) {
|
|
640
|
+
return element.valueAsDate;
|
|
641
|
+
} else if (typeof value === 'number') {
|
|
642
|
+
return element.valueAsNumber;
|
|
643
|
+
}
|
|
644
|
+
break;
|
|
645
|
+
}
|
|
646
|
+
return element.value;
|
|
647
|
+
}
|
|
648
|
+
function setNativeControlValue(element, value) {
|
|
649
|
+
switch (element.type) {
|
|
650
|
+
case 'checkbox':
|
|
651
|
+
element.checked = value;
|
|
652
|
+
return;
|
|
653
|
+
case 'radio':
|
|
654
|
+
element.checked = value === element.value;
|
|
655
|
+
return;
|
|
656
|
+
case 'number':
|
|
657
|
+
case 'range':
|
|
658
|
+
case 'datetime-local':
|
|
659
|
+
if (typeof value === 'number') {
|
|
660
|
+
setNativeNumberControlValue(element, value);
|
|
661
|
+
return;
|
|
662
|
+
}
|
|
663
|
+
break;
|
|
664
|
+
case 'date':
|
|
665
|
+
case 'month':
|
|
666
|
+
case 'time':
|
|
667
|
+
case 'week':
|
|
668
|
+
if (value === null || value instanceof Date) {
|
|
669
|
+
element.valueAsDate = value;
|
|
670
|
+
return;
|
|
671
|
+
} else if (typeof value === 'number') {
|
|
672
|
+
setNativeNumberControlValue(element, value);
|
|
673
|
+
return;
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
element.value = value;
|
|
677
|
+
}
|
|
678
|
+
function setNativeNumberControlValue(element, value) {
|
|
679
|
+
if (isNaN(value)) {
|
|
680
|
+
element.value = '';
|
|
681
|
+
} else {
|
|
682
|
+
element.valueAsNumber = value;
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
function setNativeDomProperty(renderer, element, name, value) {
|
|
686
|
+
switch (name) {
|
|
687
|
+
case 'name':
|
|
688
|
+
renderer.setAttribute(element, name, value);
|
|
689
|
+
break;
|
|
690
|
+
case 'disabled':
|
|
691
|
+
case 'readonly':
|
|
692
|
+
case 'required':
|
|
693
|
+
if (value) {
|
|
694
|
+
renderer.setAttribute(element, name, '');
|
|
695
|
+
} else {
|
|
696
|
+
renderer.removeAttribute(element, name);
|
|
697
|
+
}
|
|
698
|
+
break;
|
|
699
|
+
case 'max':
|
|
700
|
+
case 'min':
|
|
701
|
+
case 'minLength':
|
|
702
|
+
case 'maxLength':
|
|
703
|
+
if (value !== undefined) {
|
|
704
|
+
renderer.setAttribute(element, name, value.toString());
|
|
705
|
+
} else {
|
|
706
|
+
renderer.removeAttribute(element, name);
|
|
707
|
+
}
|
|
708
|
+
break;
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
function customControlCreate(host, parent) {
|
|
713
|
+
host.listenToCustomControlModel(value => parent.state().controlValue.set(value));
|
|
714
|
+
host.listenToCustomControlOutput('touchedChange', () => parent.state().markAsTouched());
|
|
715
|
+
parent.registerAsBinding(host.customControl);
|
|
716
|
+
const bindings = createBindings();
|
|
717
|
+
return () => {
|
|
718
|
+
const state = parent.state();
|
|
719
|
+
const controlValue = state.controlValue();
|
|
720
|
+
if (bindingUpdated(bindings, 'controlValue', controlValue)) {
|
|
721
|
+
host.setCustomControlModelInput(controlValue);
|
|
722
|
+
}
|
|
723
|
+
for (const name of CONTROL_BINDING_NAMES) {
|
|
724
|
+
let value;
|
|
725
|
+
if (name === 'errors') {
|
|
726
|
+
value = parent.errors();
|
|
727
|
+
} else {
|
|
728
|
+
value = readFieldStateBindingValue(state, name);
|
|
729
|
+
}
|
|
730
|
+
if (bindingUpdated(bindings, name, value)) {
|
|
731
|
+
host.setInputOnDirectives(name, value);
|
|
732
|
+
if (parent.elementAcceptsNativeProperty(name) && !host.customControlHasInput(name)) {
|
|
733
|
+
setNativeDomProperty(parent.renderer, parent.nativeFormElement, name, value);
|
|
734
|
+
}
|
|
735
|
+
}
|
|
736
|
+
}
|
|
737
|
+
};
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
function cvaControlCreate(host, parent) {
|
|
741
|
+
parent.controlValueAccessor.registerOnChange(value => parent.state().controlValue.set(value));
|
|
742
|
+
parent.controlValueAccessor.registerOnTouched(() => parent.state().markAsTouched());
|
|
743
|
+
parent.registerAsBinding();
|
|
744
|
+
const bindings = createBindings();
|
|
745
|
+
return () => {
|
|
746
|
+
const fieldState = parent.state();
|
|
747
|
+
const value = fieldState.value();
|
|
748
|
+
if (bindingUpdated(bindings, 'controlValue', value)) {
|
|
749
|
+
untracked(() => parent.controlValueAccessor.writeValue(value));
|
|
750
|
+
}
|
|
751
|
+
for (const name of CONTROL_BINDING_NAMES) {
|
|
752
|
+
const value = readFieldStateBindingValue(fieldState, name);
|
|
753
|
+
if (bindingUpdated(bindings, name, value)) {
|
|
754
|
+
const propertyWasSet = host.setInputOnDirectives(name, value);
|
|
755
|
+
if (name === 'disabled' && parent.controlValueAccessor.setDisabledState) {
|
|
756
|
+
untracked(() => parent.controlValueAccessor.setDisabledState(value));
|
|
757
|
+
} else if (!propertyWasSet && parent.elementAcceptsNativeProperty(name)) {
|
|
758
|
+
setNativeDomProperty(parent.renderer, parent.nativeFormElement, name, value);
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
};
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function observeSelectMutations(select, onMutation, destroyRef) {
|
|
766
|
+
if (typeof MutationObserver !== 'function') {
|
|
767
|
+
return;
|
|
768
|
+
}
|
|
769
|
+
const observer = new MutationObserver(mutations => {
|
|
770
|
+
if (mutations.some(m => isRelevantSelectMutation(m))) {
|
|
771
|
+
onMutation();
|
|
772
|
+
}
|
|
773
|
+
});
|
|
774
|
+
observer.observe(select, {
|
|
775
|
+
attributes: true,
|
|
776
|
+
attributeFilter: ['value'],
|
|
777
|
+
characterData: true,
|
|
778
|
+
childList: true,
|
|
779
|
+
subtree: true
|
|
780
|
+
});
|
|
781
|
+
destroyRef.onDestroy(() => observer.disconnect());
|
|
782
|
+
}
|
|
783
|
+
function isRelevantSelectMutation(mutation) {
|
|
784
|
+
if (mutation.type === 'childList' || mutation.type === 'characterData') {
|
|
785
|
+
if (mutation.target instanceof Comment) {
|
|
786
|
+
return false;
|
|
787
|
+
}
|
|
788
|
+
for (const node of mutation.addedNodes) {
|
|
789
|
+
if (!(node instanceof Comment)) {
|
|
790
|
+
return true;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
for (const node of mutation.removedNodes) {
|
|
794
|
+
if (!(node instanceof Comment)) {
|
|
795
|
+
return true;
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
return false;
|
|
799
|
+
}
|
|
800
|
+
if (mutation.type === 'attributes' && mutation.target instanceof HTMLOptionElement) {
|
|
801
|
+
return true;
|
|
802
|
+
}
|
|
803
|
+
return false;
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
function nativeControlCreate(host, parent) {
|
|
807
|
+
let updateMode = false;
|
|
808
|
+
const input = parent.nativeFormElement;
|
|
809
|
+
host.listenToDom('input', () => {
|
|
810
|
+
const state = parent.state();
|
|
811
|
+
state.controlValue.set(getNativeControlValue(input, state.value));
|
|
812
|
+
});
|
|
813
|
+
host.listenToDom('blur', () => parent.state().markAsTouched());
|
|
814
|
+
parent.registerAsBinding();
|
|
815
|
+
if (input.tagName === 'SELECT') {
|
|
816
|
+
observeSelectMutations(input, () => {
|
|
817
|
+
if (!updateMode) {
|
|
818
|
+
return;
|
|
819
|
+
}
|
|
820
|
+
input.value = parent.state().controlValue();
|
|
821
|
+
}, parent.destroyRef);
|
|
822
|
+
}
|
|
823
|
+
const bindings = createBindings();
|
|
824
|
+
return () => {
|
|
825
|
+
const state = parent.state();
|
|
826
|
+
const controlValue = state.controlValue();
|
|
827
|
+
if (bindingUpdated(bindings, 'controlValue', controlValue)) {
|
|
828
|
+
setNativeControlValue(input, controlValue);
|
|
829
|
+
}
|
|
830
|
+
for (const name of CONTROL_BINDING_NAMES) {
|
|
831
|
+
const value = readFieldStateBindingValue(state, name);
|
|
832
|
+
if (bindingUpdated(bindings, name, value)) {
|
|
833
|
+
host.setInputOnDirectives(name, value);
|
|
834
|
+
if (parent.elementAcceptsNativeProperty(name)) {
|
|
835
|
+
setNativeDomProperty(parent.renderer, input, name, value);
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
updateMode = true;
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
const ɵNgFieldDirective = Symbol();
|
|
844
|
+
const FORM_FIELD = new InjectionToken(typeof ngDevMode !== 'undefined' && ngDevMode ? 'FORM_FIELD' : '');
|
|
845
|
+
class FormField {
|
|
846
|
+
fieldTree = input.required({
|
|
847
|
+
...(ngDevMode ? {
|
|
848
|
+
debugName: "fieldTree"
|
|
849
|
+
} : {}),
|
|
850
|
+
alias: 'formField'
|
|
851
|
+
});
|
|
852
|
+
renderer = inject(Renderer2);
|
|
853
|
+
destroyRef = inject(DestroyRef);
|
|
854
|
+
state = computed(() => this.fieldTree()(), ...(ngDevMode ? [{
|
|
855
|
+
debugName: "state"
|
|
856
|
+
}] : []));
|
|
857
|
+
injector = inject(Injector);
|
|
858
|
+
element = inject(ElementRef).nativeElement;
|
|
859
|
+
elementIsNativeFormElement = isNativeFormElement(this.element);
|
|
860
|
+
elementAcceptsNumericValues = isNumericFormElement(this.element);
|
|
861
|
+
elementAcceptsTextualValues = isTextualFormElement(this.element);
|
|
862
|
+
nativeFormElement = this.elementIsNativeFormElement ? this.element : undefined;
|
|
863
|
+
focuser = options => this.element.focus(options);
|
|
864
|
+
controlValueAccessors = inject(NG_VALUE_ACCESSOR, {
|
|
865
|
+
optional: true,
|
|
866
|
+
self: true
|
|
867
|
+
});
|
|
868
|
+
config = inject(SIGNAL_FORMS_CONFIG, {
|
|
869
|
+
optional: true
|
|
870
|
+
});
|
|
871
|
+
parseErrorsSource = signal(undefined, ...(ngDevMode ? [{
|
|
872
|
+
debugName: "parseErrorsSource"
|
|
873
|
+
}] : []));
|
|
874
|
+
_interopNgControl;
|
|
875
|
+
get interopNgControl() {
|
|
876
|
+
return this._interopNgControl ??= new InteropNgControl(this.state);
|
|
877
|
+
}
|
|
878
|
+
parseErrors = computed(() => this.parseErrorsSource()?.().map(err => ({
|
|
879
|
+
...err,
|
|
880
|
+
fieldTree: untracked(this.fieldTree),
|
|
881
|
+
formField: this
|
|
882
|
+
})) ?? [], ...(ngDevMode ? [{
|
|
883
|
+
debugName: "parseErrors"
|
|
884
|
+
}] : []));
|
|
885
|
+
errors = computed(() => this.state().errors().filter(err => !err.formField || err.formField === this), ...(ngDevMode ? [{
|
|
886
|
+
debugName: "errors"
|
|
887
|
+
}] : []));
|
|
888
|
+
isFieldBinding = false;
|
|
889
|
+
get controlValueAccessor() {
|
|
890
|
+
return this.controlValueAccessors?.[0] ?? this.interopNgControl?.valueAccessor ?? undefined;
|
|
891
|
+
}
|
|
892
|
+
installClassBindingEffect() {
|
|
893
|
+
const classes = Object.entries(this.config?.classes ?? {}).map(([className, computation]) => [className, computed(() => computation(this))]);
|
|
894
|
+
if (classes.length === 0) {
|
|
895
|
+
return;
|
|
896
|
+
}
|
|
897
|
+
const bindings = createBindings();
|
|
898
|
+
afterRenderEffect({
|
|
899
|
+
write: () => {
|
|
900
|
+
for (const [className, computation] of classes) {
|
|
901
|
+
const active = computation();
|
|
902
|
+
if (bindingUpdated(bindings, className, active)) {
|
|
903
|
+
if (active) {
|
|
904
|
+
this.renderer.addClass(this.element, className);
|
|
905
|
+
} else {
|
|
906
|
+
this.renderer.removeClass(this.element, className);
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
}, {
|
|
912
|
+
injector: this.injector
|
|
913
|
+
});
|
|
914
|
+
}
|
|
915
|
+
focus(options) {
|
|
916
|
+
this.focuser(options);
|
|
917
|
+
}
|
|
918
|
+
registerAsBinding(bindingOptions) {
|
|
919
|
+
if (this.isFieldBinding) {
|
|
920
|
+
throw new _RuntimeError(1913, ngDevMode && 'FormField already registered as a binding');
|
|
921
|
+
}
|
|
922
|
+
this.isFieldBinding = true;
|
|
923
|
+
this.installClassBindingEffect();
|
|
924
|
+
if (bindingOptions?.focus) {
|
|
925
|
+
this.focuser = bindingOptions.focus;
|
|
926
|
+
}
|
|
927
|
+
effect(onCleanup => {
|
|
928
|
+
const fieldNode = this.state();
|
|
929
|
+
fieldNode.nodeState.formFieldBindings.update(controls => [...controls, this]);
|
|
930
|
+
onCleanup(() => {
|
|
931
|
+
fieldNode.nodeState.formFieldBindings.update(controls => controls.filter(c => c !== this));
|
|
932
|
+
});
|
|
933
|
+
}, {
|
|
934
|
+
injector: this.injector
|
|
935
|
+
});
|
|
936
|
+
}
|
|
937
|
+
[ɵNgFieldDirective];
|
|
938
|
+
ɵngControlCreate(host) {
|
|
939
|
+
if (host.hasPassThrough) {
|
|
940
|
+
return;
|
|
941
|
+
}
|
|
942
|
+
if (this.controlValueAccessor) {
|
|
943
|
+
this.ɵngControlUpdate = cvaControlCreate(host, this);
|
|
944
|
+
} else if (host.customControl) {
|
|
945
|
+
this.ɵngControlUpdate = customControlCreate(host, this);
|
|
946
|
+
} else if (this.elementIsNativeFormElement) {
|
|
947
|
+
this.ɵngControlUpdate = nativeControlCreate(host, this);
|
|
948
|
+
} else {
|
|
949
|
+
throw new _RuntimeError(1914, ngDevMode && `${host.descriptor} is an invalid [formField] directive host. The host must be a native form control ` + `(such as <input>', '<select>', or '<textarea>') or a custom form control with a 'value' or ` + `'checked' model.`);
|
|
950
|
+
}
|
|
951
|
+
}
|
|
952
|
+
ɵngControlUpdate;
|
|
953
|
+
elementAcceptsNativeProperty(key) {
|
|
954
|
+
if (!this.elementIsNativeFormElement) {
|
|
955
|
+
return false;
|
|
956
|
+
}
|
|
957
|
+
switch (key) {
|
|
958
|
+
case 'min':
|
|
959
|
+
case 'max':
|
|
960
|
+
return this.elementAcceptsNumericValues;
|
|
961
|
+
case 'minLength':
|
|
962
|
+
case 'maxLength':
|
|
963
|
+
return this.elementAcceptsTextualValues;
|
|
964
|
+
case 'disabled':
|
|
965
|
+
case 'required':
|
|
966
|
+
case 'readonly':
|
|
967
|
+
case 'name':
|
|
968
|
+
return true;
|
|
969
|
+
default:
|
|
970
|
+
return false;
|
|
971
|
+
}
|
|
972
|
+
}
|
|
973
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
974
|
+
minVersion: "12.0.0",
|
|
975
|
+
version: "21.2.0-next.3",
|
|
976
|
+
ngImport: i0,
|
|
977
|
+
type: FormField,
|
|
978
|
+
deps: [],
|
|
979
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
980
|
+
});
|
|
981
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
982
|
+
minVersion: "17.1.0",
|
|
983
|
+
version: "21.2.0-next.3",
|
|
984
|
+
type: FormField,
|
|
985
|
+
isStandalone: true,
|
|
986
|
+
selector: "[formField]",
|
|
987
|
+
inputs: {
|
|
988
|
+
fieldTree: {
|
|
989
|
+
classPropertyName: "fieldTree",
|
|
990
|
+
publicName: "formField",
|
|
991
|
+
isSignal: true,
|
|
992
|
+
isRequired: true,
|
|
993
|
+
transformFunction: null
|
|
994
|
+
}
|
|
995
|
+
},
|
|
996
|
+
providers: [{
|
|
997
|
+
provide: FORM_FIELD,
|
|
998
|
+
useExisting: FormField
|
|
999
|
+
}, {
|
|
1000
|
+
provide: NgControl,
|
|
1001
|
+
useFactory: () => inject(FormField).interopNgControl
|
|
1002
|
+
}, {
|
|
1003
|
+
provide: FORM_FIELD_PARSE_ERRORS,
|
|
1004
|
+
useFactory: () => inject(FormField).parseErrorsSource
|
|
1005
|
+
}],
|
|
1006
|
+
exportAs: ["formField"],
|
|
1007
|
+
controlCreate: {
|
|
1008
|
+
passThroughInput: "formField"
|
|
1009
|
+
},
|
|
1010
|
+
ngImport: i0
|
|
1011
|
+
});
|
|
1012
|
+
}
|
|
1013
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1014
|
+
minVersion: "12.0.0",
|
|
1015
|
+
version: "21.2.0-next.3",
|
|
1016
|
+
ngImport: i0,
|
|
1017
|
+
type: FormField,
|
|
1018
|
+
decorators: [{
|
|
1019
|
+
type: Directive,
|
|
1020
|
+
args: [{
|
|
1021
|
+
selector: '[formField]',
|
|
1022
|
+
exportAs: 'formField',
|
|
1023
|
+
providers: [{
|
|
1024
|
+
provide: FORM_FIELD,
|
|
1025
|
+
useExisting: FormField
|
|
1026
|
+
}, {
|
|
1027
|
+
provide: NgControl,
|
|
1028
|
+
useFactory: () => inject(FormField).interopNgControl
|
|
1029
|
+
}, {
|
|
1030
|
+
provide: FORM_FIELD_PARSE_ERRORS,
|
|
1031
|
+
useFactory: () => inject(FormField).parseErrorsSource
|
|
1032
|
+
}]
|
|
1033
|
+
}]
|
|
1034
|
+
}],
|
|
1035
|
+
propDecorators: {
|
|
1036
|
+
fieldTree: [{
|
|
1037
|
+
type: i0.Input,
|
|
1038
|
+
args: [{
|
|
1039
|
+
isSignal: true,
|
|
1040
|
+
alias: "formField",
|
|
1041
|
+
required: true
|
|
1042
|
+
}]
|
|
1043
|
+
}]
|
|
1044
|
+
}
|
|
1045
|
+
});
|
|
1046
|
+
|
|
1047
|
+
class FormRoot {
|
|
1048
|
+
fieldTree = input.required({
|
|
1049
|
+
...(ngDevMode ? {
|
|
1050
|
+
debugName: "fieldTree"
|
|
1051
|
+
} : {}),
|
|
1052
|
+
alias: 'formRoot'
|
|
1053
|
+
});
|
|
1054
|
+
onSubmit(event) {
|
|
1055
|
+
event.preventDefault();
|
|
1056
|
+
submit(this.fieldTree());
|
|
1057
|
+
}
|
|
1058
|
+
static ɵfac = i0.ɵɵngDeclareFactory({
|
|
1059
|
+
minVersion: "12.0.0",
|
|
1060
|
+
version: "21.2.0-next.3",
|
|
1061
|
+
ngImport: i0,
|
|
1062
|
+
type: FormRoot,
|
|
1063
|
+
deps: [],
|
|
1064
|
+
target: i0.ɵɵFactoryTarget.Directive
|
|
1065
|
+
});
|
|
1066
|
+
static ɵdir = i0.ɵɵngDeclareDirective({
|
|
1067
|
+
minVersion: "17.1.0",
|
|
1068
|
+
version: "21.2.0-next.3",
|
|
1069
|
+
type: FormRoot,
|
|
1070
|
+
isStandalone: true,
|
|
1071
|
+
selector: "form[formRoot]",
|
|
1072
|
+
inputs: {
|
|
1073
|
+
fieldTree: {
|
|
1074
|
+
classPropertyName: "fieldTree",
|
|
1075
|
+
publicName: "formRoot",
|
|
1076
|
+
isSignal: true,
|
|
1077
|
+
isRequired: true,
|
|
1078
|
+
transformFunction: null
|
|
1079
|
+
}
|
|
1080
|
+
},
|
|
1081
|
+
host: {
|
|
1082
|
+
attributes: {
|
|
1083
|
+
"novalidate": ""
|
|
1084
|
+
},
|
|
1085
|
+
listeners: {
|
|
1086
|
+
"submit": "onSubmit($event)"
|
|
1087
|
+
}
|
|
1088
|
+
},
|
|
1089
|
+
ngImport: i0
|
|
1090
|
+
});
|
|
1091
|
+
}
|
|
1092
|
+
i0.ɵɵngDeclareClassMetadata({
|
|
1093
|
+
minVersion: "12.0.0",
|
|
1094
|
+
version: "21.2.0-next.3",
|
|
1095
|
+
ngImport: i0,
|
|
1096
|
+
type: FormRoot,
|
|
1097
|
+
decorators: [{
|
|
1098
|
+
type: Directive,
|
|
1099
|
+
args: [{
|
|
1100
|
+
selector: 'form[formRoot]',
|
|
1101
|
+
host: {
|
|
1102
|
+
'novalidate': '',
|
|
1103
|
+
'(submit)': 'onSubmit($event)'
|
|
1104
|
+
}
|
|
1105
|
+
}]
|
|
1106
|
+
}],
|
|
1107
|
+
propDecorators: {
|
|
1108
|
+
fieldTree: [{
|
|
1109
|
+
type: i0.Input,
|
|
1110
|
+
args: [{
|
|
1111
|
+
isSignal: true,
|
|
1112
|
+
alias: "formRoot",
|
|
1113
|
+
required: true
|
|
1114
|
+
}]
|
|
1115
|
+
}]
|
|
1116
|
+
}
|
|
1117
|
+
});
|
|
1118
|
+
|
|
1119
|
+
export { BaseNgValidationError, EmailValidationError, FORM_FIELD, FormField, FormRoot, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MaxLengthValidationError, MaxValidationError, MinLengthValidationError, MinValidationError, NgValidationError, PATTERN, PatternValidationError, REQUIRED, RequiredValidationError, StandardSchemaValidationError, createManagedMetadataKey, createMetadataKey, debounce, disabled, email, emailError, hidden, max, maxError, maxLength, maxLengthError, metadata, min, minError, minLength, minLengthError, pattern, patternError, provideSignalFormsConfig, readonly, required, requiredError, standardSchemaError, submit, transformedValue, validate, validateAsync, validateHttp, validateStandardSchema, validateTree, ɵNgFieldDirective };
|
|
675
1120
|
//# sourceMappingURL=signals.mjs.map
|