@angular/forms 21.1.0-next.1 → 21.1.0-next.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/fesm2022/_structure-chunk.mjs +453 -385
- package/fesm2022/_structure-chunk.mjs.map +1 -1
- package/fesm2022/forms.mjs +133 -133
- package/fesm2022/forms.mjs.map +1 -1
- package/fesm2022/signals-compat.mjs +9 -6
- package/fesm2022/signals-compat.mjs.map +1 -1
- package/fesm2022/signals.mjs +276 -293
- package/fesm2022/signals.mjs.map +1 -1
- package/package.json +4 -4
- package/types/_structure-chunk.d.ts +788 -708
- package/types/forms.d.ts +1 -1
- package/types/signals-compat.d.ts +1 -1
- package/types/signals.d.ts +191 -225
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @license Angular v21.1.0-next.
|
|
2
|
+
* @license Angular v21.1.0-next.2
|
|
3
3
|
* (c) 2010-2025 Google LLC. https://angular.dev/
|
|
4
4
|
* License: MIT
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { untracked, computed, runInInjectionContext, Injector, linkedSignal, signal, APP_ID, effect, inject } from '@angular/core';
|
|
8
8
|
import { AbstractControl } from '@angular/forms';
|
|
9
9
|
import { SIGNAL } from '@angular/core/primitives/signals';
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
function isObject(value) {
|
|
15
|
-
return (typeof value === 'object' || typeof value === 'function') && value != null;
|
|
11
|
+
let boundPathDepth = 0;
|
|
12
|
+
function getBoundPathDepth() {
|
|
13
|
+
return boundPathDepth;
|
|
16
14
|
}
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
for (const child of childrenMap.values()) {
|
|
25
|
-
if (shortCircuit?.(value)) {
|
|
26
|
-
break;
|
|
15
|
+
function setBoundPathDepthForResolution(fn, depth) {
|
|
16
|
+
return (...args) => {
|
|
17
|
+
try {
|
|
18
|
+
boundPathDepth = depth;
|
|
19
|
+
return fn(...args);
|
|
20
|
+
} finally {
|
|
21
|
+
boundPathDepth = 0;
|
|
27
22
|
}
|
|
28
|
-
|
|
29
|
-
}
|
|
30
|
-
return value;
|
|
23
|
+
};
|
|
31
24
|
}
|
|
25
|
+
|
|
32
26
|
function shortCircuitFalse(value) {
|
|
33
27
|
return !value;
|
|
34
28
|
}
|
|
@@ -42,131 +36,11 @@ function getInjectorFromOptions(options) {
|
|
|
42
36
|
return options.parent.structure.root.structure.injector;
|
|
43
37
|
}
|
|
44
38
|
|
|
45
|
-
function
|
|
46
|
-
|
|
47
|
-
return 'invalid';
|
|
48
|
-
}
|
|
49
|
-
if (state.pending()) {
|
|
50
|
-
return 'unknown';
|
|
51
|
-
}
|
|
52
|
-
return 'valid';
|
|
53
|
-
}
|
|
54
|
-
class FieldValidationState {
|
|
55
|
-
node;
|
|
56
|
-
constructor(node) {
|
|
57
|
-
this.node = node;
|
|
58
|
-
}
|
|
59
|
-
rawSyncTreeErrors = computed(() => {
|
|
60
|
-
if (this.shouldSkipValidation()) {
|
|
61
|
-
return [];
|
|
62
|
-
}
|
|
63
|
-
return [...this.node.logicNode.logic.syncTreeErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawSyncTreeErrors() ?? [])];
|
|
64
|
-
}, ...(ngDevMode ? [{
|
|
65
|
-
debugName: "rawSyncTreeErrors"
|
|
66
|
-
}] : []));
|
|
67
|
-
syncErrors = computed(() => {
|
|
68
|
-
if (this.shouldSkipValidation()) {
|
|
69
|
-
return [];
|
|
70
|
-
}
|
|
71
|
-
return [...this.node.logicNode.logic.syncErrors.compute(this.node.context), ...this.syncTreeErrors(), ...normalizeErrors(this.node.submitState.serverErrors())];
|
|
72
|
-
}, ...(ngDevMode ? [{
|
|
73
|
-
debugName: "syncErrors"
|
|
74
|
-
}] : []));
|
|
75
|
-
syncValid = computed(() => {
|
|
76
|
-
if (this.shouldSkipValidation()) {
|
|
77
|
-
return true;
|
|
78
|
-
}
|
|
79
|
-
return reduceChildren(this.node, this.syncErrors().length === 0, (child, value) => value && child.validationState.syncValid(), shortCircuitFalse);
|
|
80
|
-
}, ...(ngDevMode ? [{
|
|
81
|
-
debugName: "syncValid"
|
|
82
|
-
}] : []));
|
|
83
|
-
syncTreeErrors = computed(() => this.rawSyncTreeErrors().filter(err => err.field === this.node.fieldProxy), ...(ngDevMode ? [{
|
|
84
|
-
debugName: "syncTreeErrors"
|
|
85
|
-
}] : []));
|
|
86
|
-
rawAsyncErrors = computed(() => {
|
|
87
|
-
if (this.shouldSkipValidation()) {
|
|
88
|
-
return [];
|
|
89
|
-
}
|
|
90
|
-
return [...this.node.logicNode.logic.asyncErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawAsyncErrors() ?? [])];
|
|
91
|
-
}, ...(ngDevMode ? [{
|
|
92
|
-
debugName: "rawAsyncErrors"
|
|
93
|
-
}] : []));
|
|
94
|
-
asyncErrors = computed(() => {
|
|
95
|
-
if (this.shouldSkipValidation()) {
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
|
-
return this.rawAsyncErrors().filter(err => err === 'pending' || err.field === this.node.fieldProxy);
|
|
99
|
-
}, ...(ngDevMode ? [{
|
|
100
|
-
debugName: "asyncErrors"
|
|
101
|
-
}] : []));
|
|
102
|
-
errors = computed(() => [...this.syncErrors(), ...this.asyncErrors().filter(err => err !== 'pending')], ...(ngDevMode ? [{
|
|
103
|
-
debugName: "errors"
|
|
104
|
-
}] : []));
|
|
105
|
-
errorSummary = computed(() => reduceChildren(this.node, this.errors(), (child, result) => [...result, ...child.errorSummary()]), ...(ngDevMode ? [{
|
|
106
|
-
debugName: "errorSummary"
|
|
107
|
-
}] : []));
|
|
108
|
-
pending = computed(() => reduceChildren(this.node, this.asyncErrors().includes('pending'), (child, value) => value || child.validationState.asyncErrors().includes('pending')), ...(ngDevMode ? [{
|
|
109
|
-
debugName: "pending"
|
|
110
|
-
}] : []));
|
|
111
|
-
status = computed(() => {
|
|
112
|
-
if (this.shouldSkipValidation()) {
|
|
113
|
-
return 'valid';
|
|
114
|
-
}
|
|
115
|
-
let ownStatus = calculateValidationSelfStatus(this);
|
|
116
|
-
return reduceChildren(this.node, ownStatus, (child, value) => {
|
|
117
|
-
if (value === 'invalid' || child.validationState.status() === 'invalid') {
|
|
118
|
-
return 'invalid';
|
|
119
|
-
} else if (value === 'unknown' || child.validationState.status() === 'unknown') {
|
|
120
|
-
return 'unknown';
|
|
121
|
-
}
|
|
122
|
-
return 'valid';
|
|
123
|
-
}, v => v === 'invalid');
|
|
124
|
-
}, ...(ngDevMode ? [{
|
|
125
|
-
debugName: "status"
|
|
126
|
-
}] : []));
|
|
127
|
-
valid = computed(() => this.status() === 'valid', ...(ngDevMode ? [{
|
|
128
|
-
debugName: "valid"
|
|
129
|
-
}] : []));
|
|
130
|
-
invalid = computed(() => this.status() === 'invalid', ...(ngDevMode ? [{
|
|
131
|
-
debugName: "invalid"
|
|
132
|
-
}] : []));
|
|
133
|
-
shouldSkipValidation = computed(() => this.node.hidden() || this.node.disabled() || this.node.readonly(), ...(ngDevMode ? [{
|
|
134
|
-
debugName: "shouldSkipValidation"
|
|
135
|
-
}] : []));
|
|
136
|
-
}
|
|
137
|
-
function normalizeErrors(error) {
|
|
138
|
-
if (error === undefined) {
|
|
139
|
-
return [];
|
|
140
|
-
}
|
|
141
|
-
if (isArray(error)) {
|
|
142
|
-
return error;
|
|
143
|
-
}
|
|
144
|
-
return [error];
|
|
145
|
-
}
|
|
146
|
-
function addDefaultField(errors, field) {
|
|
147
|
-
if (isArray(errors)) {
|
|
148
|
-
for (const error of errors) {
|
|
149
|
-
error.field ??= field;
|
|
150
|
-
}
|
|
151
|
-
} else if (errors) {
|
|
152
|
-
errors.field ??= field;
|
|
153
|
-
}
|
|
154
|
-
return errors;
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
let boundPathDepth = 0;
|
|
158
|
-
function getBoundPathDepth() {
|
|
159
|
-
return boundPathDepth;
|
|
39
|
+
function isArray(value) {
|
|
40
|
+
return Array.isArray(value);
|
|
160
41
|
}
|
|
161
|
-
function
|
|
162
|
-
return (
|
|
163
|
-
try {
|
|
164
|
-
boundPathDepth = depth;
|
|
165
|
-
return fn(...args);
|
|
166
|
-
} finally {
|
|
167
|
-
boundPathDepth = 0;
|
|
168
|
-
}
|
|
169
|
-
};
|
|
42
|
+
function isObject(value) {
|
|
43
|
+
return (typeof value === 'object' || typeof value === 'function') && value != null;
|
|
170
44
|
}
|
|
171
45
|
|
|
172
46
|
const DYNAMIC = Symbol();
|
|
@@ -229,10 +103,10 @@ class ArrayMergeLogic extends ArrayMergeIgnoreLogic {
|
|
|
229
103
|
super(predicates, undefined);
|
|
230
104
|
}
|
|
231
105
|
}
|
|
232
|
-
class
|
|
106
|
+
class MetadataMergeLogic extends AbstractLogic {
|
|
233
107
|
key;
|
|
234
108
|
get defaultValue() {
|
|
235
|
-
return this.key.getInitial();
|
|
109
|
+
return this.key.reducer.getInitial();
|
|
236
110
|
}
|
|
237
111
|
constructor(predicates, key) {
|
|
238
112
|
super(predicates);
|
|
@@ -240,13 +114,13 @@ class AggregateMetadataMergeLogic extends AbstractLogic {
|
|
|
240
114
|
}
|
|
241
115
|
compute(ctx) {
|
|
242
116
|
if (this.fns.length === 0) {
|
|
243
|
-
return this.key.getInitial();
|
|
117
|
+
return this.key.reducer.getInitial();
|
|
244
118
|
}
|
|
245
|
-
let acc = this.key.getInitial();
|
|
119
|
+
let acc = this.key.reducer.getInitial();
|
|
246
120
|
for (let i = 0; i < this.fns.length; i++) {
|
|
247
121
|
const item = this.fns[i](ctx);
|
|
248
122
|
if (item !== IGNORED) {
|
|
249
|
-
acc = this.key.reduce(acc, item);
|
|
123
|
+
acc = this.key.reducer.reduce(acc, item);
|
|
250
124
|
}
|
|
251
125
|
}
|
|
252
126
|
return acc;
|
|
@@ -278,8 +152,7 @@ class LogicContainer {
|
|
|
278
152
|
syncErrors;
|
|
279
153
|
syncTreeErrors;
|
|
280
154
|
asyncErrors;
|
|
281
|
-
|
|
282
|
-
metadataFactories = new Map();
|
|
155
|
+
metadata = new Map();
|
|
283
156
|
constructor(predicates) {
|
|
284
157
|
this.predicates = predicates;
|
|
285
158
|
this.hidden = new BooleanOrLogic(predicates);
|
|
@@ -289,26 +162,17 @@ class LogicContainer {
|
|
|
289
162
|
this.syncTreeErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
|
|
290
163
|
this.asyncErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
|
|
291
164
|
}
|
|
292
|
-
|
|
293
|
-
return this.
|
|
294
|
-
}
|
|
295
|
-
getAggregateMetadataEntries() {
|
|
296
|
-
return this.aggregateMetadataKeys.entries();
|
|
297
|
-
}
|
|
298
|
-
getMetadataFactoryEntries() {
|
|
299
|
-
return this.metadataFactories.entries();
|
|
165
|
+
hasMetadata(key) {
|
|
166
|
+
return this.metadata.has(key);
|
|
300
167
|
}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
this.aggregateMetadataKeys.set(key, new AggregateMetadataMergeLogic(this.predicates, key));
|
|
304
|
-
}
|
|
305
|
-
return this.aggregateMetadataKeys.get(key);
|
|
168
|
+
getMetadataKeys() {
|
|
169
|
+
return this.metadata.keys();
|
|
306
170
|
}
|
|
307
|
-
|
|
308
|
-
if (this.
|
|
309
|
-
|
|
171
|
+
getMetadata(key) {
|
|
172
|
+
if (!this.metadata.has(key)) {
|
|
173
|
+
this.metadata.set(key, new MetadataMergeLogic(this.predicates, key));
|
|
310
174
|
}
|
|
311
|
-
this.
|
|
175
|
+
return this.metadata.get(key);
|
|
312
176
|
}
|
|
313
177
|
mergeIn(other) {
|
|
314
178
|
this.hidden.mergeIn(other.hidden);
|
|
@@ -317,11 +181,9 @@ class LogicContainer {
|
|
|
317
181
|
this.syncErrors.mergeIn(other.syncErrors);
|
|
318
182
|
this.syncTreeErrors.mergeIn(other.syncTreeErrors);
|
|
319
183
|
this.asyncErrors.mergeIn(other.asyncErrors);
|
|
320
|
-
for (const
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
for (const [key, metadataFactory] of other.getMetadataFactoryEntries()) {
|
|
324
|
-
this.addMetadataFactory(key, metadataFactory);
|
|
184
|
+
for (const key of other.getMetadataKeys()) {
|
|
185
|
+
const metadataLogic = other.metadata.get(key);
|
|
186
|
+
this.getMetadata(key).mergeIn(metadataLogic);
|
|
325
187
|
}
|
|
326
188
|
}
|
|
327
189
|
}
|
|
@@ -359,11 +221,8 @@ class LogicNodeBuilder extends AbstractLogicNodeBuilder {
|
|
|
359
221
|
addAsyncErrorRule(logic) {
|
|
360
222
|
this.getCurrent().addAsyncErrorRule(logic);
|
|
361
223
|
}
|
|
362
|
-
|
|
363
|
-
this.getCurrent().
|
|
364
|
-
}
|
|
365
|
-
addMetadataFactory(key, factory) {
|
|
366
|
-
this.getCurrent().addMetadataFactory(key, factory);
|
|
224
|
+
addMetadataRule(key, logic) {
|
|
225
|
+
this.getCurrent().addMetadataRule(key, logic);
|
|
367
226
|
}
|
|
368
227
|
getChild(key) {
|
|
369
228
|
if (key === DYNAMIC) {
|
|
@@ -435,11 +294,8 @@ class NonMergeableLogicNodeBuilder extends AbstractLogicNodeBuilder {
|
|
|
435
294
|
addAsyncErrorRule(logic) {
|
|
436
295
|
this.logic.asyncErrors.push(setBoundPathDepthForResolution(logic, this.depth));
|
|
437
296
|
}
|
|
438
|
-
|
|
439
|
-
this.logic.
|
|
440
|
-
}
|
|
441
|
-
addMetadataFactory(key, factory) {
|
|
442
|
-
this.logic.addMetadataFactory(key, setBoundPathDepthForResolution(factory, this.depth));
|
|
297
|
+
addMetadataRule(key, logic) {
|
|
298
|
+
this.logic.getMetadata(key).push(setBoundPathDepthForResolution(logic, this.depth));
|
|
443
299
|
}
|
|
444
300
|
getChild(key) {
|
|
445
301
|
if (!this.children.has(key)) {
|
|
@@ -657,64 +513,196 @@ function assertPathIsCurrent(path) {
|
|
|
657
513
|
}
|
|
658
514
|
}
|
|
659
515
|
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
516
|
+
function metadata(path, key, logic) {
|
|
517
|
+
assertPathIsCurrent(path);
|
|
518
|
+
const pathNode = FieldPathNode.unwrapFieldPath(path);
|
|
519
|
+
pathNode.builder.addMetadataRule(key, logic);
|
|
520
|
+
return key;
|
|
663
521
|
}
|
|
664
|
-
|
|
665
|
-
|
|
522
|
+
const MetadataReducer = {
|
|
523
|
+
list() {
|
|
524
|
+
return {
|
|
525
|
+
reduce: (acc, item) => item === undefined ? acc : [...acc, item],
|
|
526
|
+
getInitial: () => []
|
|
527
|
+
};
|
|
528
|
+
},
|
|
529
|
+
min() {
|
|
530
|
+
return {
|
|
531
|
+
reduce: (acc, item) => {
|
|
532
|
+
if (acc === undefined || item === undefined) {
|
|
533
|
+
return acc ?? item;
|
|
534
|
+
}
|
|
535
|
+
return Math.min(acc, item);
|
|
536
|
+
},
|
|
537
|
+
getInitial: () => undefined
|
|
538
|
+
};
|
|
539
|
+
},
|
|
540
|
+
max() {
|
|
541
|
+
return {
|
|
542
|
+
reduce: (prev, next) => {
|
|
543
|
+
if (prev === undefined || next === undefined) {
|
|
544
|
+
return prev ?? next;
|
|
545
|
+
}
|
|
546
|
+
return Math.max(prev, next);
|
|
547
|
+
},
|
|
548
|
+
getInitial: () => undefined
|
|
549
|
+
};
|
|
550
|
+
},
|
|
551
|
+
or() {
|
|
552
|
+
return {
|
|
553
|
+
reduce: (prev, next) => prev || next,
|
|
554
|
+
getInitial: () => false
|
|
555
|
+
};
|
|
556
|
+
},
|
|
557
|
+
and() {
|
|
558
|
+
return {
|
|
559
|
+
reduce: (prev, next) => prev && next,
|
|
560
|
+
getInitial: () => true
|
|
561
|
+
};
|
|
562
|
+
},
|
|
563
|
+
override
|
|
564
|
+
};
|
|
565
|
+
function override(getInitial) {
|
|
566
|
+
return {
|
|
567
|
+
reduce: (_, item) => item,
|
|
568
|
+
getInitial: () => getInitial?.()
|
|
569
|
+
};
|
|
666
570
|
}
|
|
667
|
-
class
|
|
668
|
-
|
|
669
|
-
|
|
571
|
+
class MetadataKey {
|
|
572
|
+
reducer;
|
|
573
|
+
create;
|
|
670
574
|
brand;
|
|
671
|
-
constructor(
|
|
672
|
-
this.
|
|
673
|
-
this.
|
|
575
|
+
constructor(reducer, create) {
|
|
576
|
+
this.reducer = reducer;
|
|
577
|
+
this.create = create;
|
|
674
578
|
}
|
|
675
579
|
}
|
|
676
|
-
function
|
|
677
|
-
return new
|
|
580
|
+
function createMetadataKey(reducer) {
|
|
581
|
+
return new MetadataKey(reducer ?? MetadataReducer.override());
|
|
678
582
|
}
|
|
679
|
-
function
|
|
680
|
-
return
|
|
583
|
+
function createManagedMetadataKey(create, reducer) {
|
|
584
|
+
return new MetadataKey(reducer ?? MetadataReducer.override(), create);
|
|
585
|
+
}
|
|
586
|
+
const REQUIRED = createMetadataKey(MetadataReducer.or());
|
|
587
|
+
const MIN = createMetadataKey(MetadataReducer.max());
|
|
588
|
+
const MAX = createMetadataKey(MetadataReducer.min());
|
|
589
|
+
const MIN_LENGTH = createMetadataKey(MetadataReducer.max());
|
|
590
|
+
const MAX_LENGTH = createMetadataKey(MetadataReducer.min());
|
|
591
|
+
const PATTERN = createMetadataKey(MetadataReducer.list());
|
|
592
|
+
|
|
593
|
+
function calculateValidationSelfStatus(state) {
|
|
594
|
+
if (state.errors().length > 0) {
|
|
595
|
+
return 'invalid';
|
|
596
|
+
}
|
|
597
|
+
if (state.pending()) {
|
|
598
|
+
return 'unknown';
|
|
599
|
+
}
|
|
600
|
+
return 'valid';
|
|
681
601
|
}
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
602
|
+
class FieldValidationState {
|
|
603
|
+
node;
|
|
604
|
+
constructor(node) {
|
|
605
|
+
this.node = node;
|
|
606
|
+
}
|
|
607
|
+
rawSyncTreeErrors = computed(() => {
|
|
608
|
+
if (this.shouldSkipValidation()) {
|
|
609
|
+
return [];
|
|
686
610
|
}
|
|
687
|
-
|
|
688
|
-
|
|
611
|
+
return [...this.node.logicNode.logic.syncTreeErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawSyncTreeErrors() ?? [])];
|
|
612
|
+
}, ...(ngDevMode ? [{
|
|
613
|
+
debugName: "rawSyncTreeErrors"
|
|
614
|
+
}] : []));
|
|
615
|
+
syncErrors = computed(() => {
|
|
616
|
+
if (this.shouldSkipValidation()) {
|
|
617
|
+
return [];
|
|
689
618
|
}
|
|
690
|
-
return
|
|
691
|
-
}, (
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
if (
|
|
696
|
-
return
|
|
619
|
+
return [...this.node.logicNode.logic.syncErrors.compute(this.node.context), ...this.syncTreeErrors(), ...normalizeErrors(this.node.submitState.serverErrors())];
|
|
620
|
+
}, ...(ngDevMode ? [{
|
|
621
|
+
debugName: "syncErrors"
|
|
622
|
+
}] : []));
|
|
623
|
+
syncValid = computed(() => {
|
|
624
|
+
if (this.shouldSkipValidation()) {
|
|
625
|
+
return true;
|
|
697
626
|
}
|
|
698
|
-
|
|
699
|
-
|
|
627
|
+
return this.node.structure.reduceChildren(this.syncErrors().length === 0, (child, value) => value && child.validationState.syncValid(), shortCircuitFalse);
|
|
628
|
+
}, ...(ngDevMode ? [{
|
|
629
|
+
debugName: "syncValid"
|
|
630
|
+
}] : []));
|
|
631
|
+
syncTreeErrors = computed(() => this.rawSyncTreeErrors().filter(err => err.field === this.node.fieldProxy), ...(ngDevMode ? [{
|
|
632
|
+
debugName: "syncTreeErrors"
|
|
633
|
+
}] : []));
|
|
634
|
+
rawAsyncErrors = computed(() => {
|
|
635
|
+
if (this.shouldSkipValidation()) {
|
|
636
|
+
return [];
|
|
700
637
|
}
|
|
701
|
-
return
|
|
702
|
-
}, (
|
|
638
|
+
return [...this.node.logicNode.logic.asyncErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawAsyncErrors() ?? [])];
|
|
639
|
+
}, ...(ngDevMode ? [{
|
|
640
|
+
debugName: "rawAsyncErrors"
|
|
641
|
+
}] : []));
|
|
642
|
+
asyncErrors = computed(() => {
|
|
643
|
+
if (this.shouldSkipValidation()) {
|
|
644
|
+
return [];
|
|
645
|
+
}
|
|
646
|
+
return this.rawAsyncErrors().filter(err => err === 'pending' || err.field === this.node.fieldProxy);
|
|
647
|
+
}, ...(ngDevMode ? [{
|
|
648
|
+
debugName: "asyncErrors"
|
|
649
|
+
}] : []));
|
|
650
|
+
errors = computed(() => [...this.syncErrors(), ...this.asyncErrors().filter(err => err !== 'pending')], ...(ngDevMode ? [{
|
|
651
|
+
debugName: "errors"
|
|
652
|
+
}] : []));
|
|
653
|
+
errorSummary = computed(() => this.node.structure.reduceChildren(this.errors(), (child, result) => [...result, ...child.errorSummary()]), ...(ngDevMode ? [{
|
|
654
|
+
debugName: "errorSummary"
|
|
655
|
+
}] : []));
|
|
656
|
+
pending = computed(() => this.node.structure.reduceChildren(this.asyncErrors().includes('pending'), (child, value) => value || child.validationState.asyncErrors().includes('pending')), ...(ngDevMode ? [{
|
|
657
|
+
debugName: "pending"
|
|
658
|
+
}] : []));
|
|
659
|
+
status = computed(() => {
|
|
660
|
+
if (this.shouldSkipValidation()) {
|
|
661
|
+
return 'valid';
|
|
662
|
+
}
|
|
663
|
+
let ownStatus = calculateValidationSelfStatus(this);
|
|
664
|
+
return this.node.structure.reduceChildren(ownStatus, (child, value) => {
|
|
665
|
+
if (value === 'invalid' || child.validationState.status() === 'invalid') {
|
|
666
|
+
return 'invalid';
|
|
667
|
+
} else if (value === 'unknown' || child.validationState.status() === 'unknown') {
|
|
668
|
+
return 'unknown';
|
|
669
|
+
}
|
|
670
|
+
return 'valid';
|
|
671
|
+
}, v => v === 'invalid');
|
|
672
|
+
}, ...(ngDevMode ? [{
|
|
673
|
+
debugName: "status"
|
|
674
|
+
}] : []));
|
|
675
|
+
valid = computed(() => this.status() === 'valid', ...(ngDevMode ? [{
|
|
676
|
+
debugName: "valid"
|
|
677
|
+
}] : []));
|
|
678
|
+
invalid = computed(() => this.status() === 'invalid', ...(ngDevMode ? [{
|
|
679
|
+
debugName: "invalid"
|
|
680
|
+
}] : []));
|
|
681
|
+
shouldSkipValidation = computed(() => this.node.hidden() || this.node.disabled() || this.node.readonly(), ...(ngDevMode ? [{
|
|
682
|
+
debugName: "shouldSkipValidation"
|
|
683
|
+
}] : []));
|
|
703
684
|
}
|
|
704
|
-
function
|
|
705
|
-
|
|
685
|
+
function normalizeErrors(error) {
|
|
686
|
+
if (error === undefined) {
|
|
687
|
+
return [];
|
|
688
|
+
}
|
|
689
|
+
if (isArray(error)) {
|
|
690
|
+
return error;
|
|
691
|
+
}
|
|
692
|
+
return [error];
|
|
706
693
|
}
|
|
707
|
-
function
|
|
708
|
-
|
|
694
|
+
function addDefaultField(errors, field) {
|
|
695
|
+
if (isArray(errors)) {
|
|
696
|
+
for (const error of errors) {
|
|
697
|
+
error.field ??= field;
|
|
698
|
+
}
|
|
699
|
+
} else if (errors) {
|
|
700
|
+
errors.field ??= field;
|
|
701
|
+
}
|
|
702
|
+
return errors;
|
|
709
703
|
}
|
|
710
|
-
const REQUIRED = orMetadataKey();
|
|
711
|
-
const MIN = maxMetadataKey();
|
|
712
|
-
const MAX = minMetadataKey();
|
|
713
|
-
const MIN_LENGTH = maxMetadataKey();
|
|
714
|
-
const MAX_LENGTH = minMetadataKey();
|
|
715
|
-
const PATTERN = listMetadataKey();
|
|
716
704
|
|
|
717
|
-
const DEBOUNCER =
|
|
705
|
+
const DEBOUNCER = createMetadataKey();
|
|
718
706
|
|
|
719
707
|
class FieldNodeContext {
|
|
720
708
|
node;
|
|
@@ -789,31 +777,28 @@ class FieldMetadataState {
|
|
|
789
777
|
metadata = new Map();
|
|
790
778
|
constructor(node) {
|
|
791
779
|
this.node = node;
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
this.
|
|
780
|
+
for (const key of this.node.logicNode.logic.getMetadataKeys()) {
|
|
781
|
+
if (key.create) {
|
|
782
|
+
const logic = this.node.logicNode.logic.getMetadata(key);
|
|
783
|
+
const result = untracked(() => runInInjectionContext(this.node.structure.injector, () => key.create(computed(() => logic.compute(this.node.context)))));
|
|
784
|
+
this.metadata.set(key, result);
|
|
795
785
|
}
|
|
796
|
-
}
|
|
786
|
+
}
|
|
797
787
|
}
|
|
798
788
|
get(key) {
|
|
799
|
-
if (key
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
}
|
|
807
|
-
this.metadata.set(key, result);
|
|
789
|
+
if (this.has(key)) {
|
|
790
|
+
if (!this.metadata.has(key)) {
|
|
791
|
+
if (key.create) {
|
|
792
|
+
throw Error('Managed metadata cannot be created lazily');
|
|
793
|
+
}
|
|
794
|
+
const logic = this.node.logicNode.logic.getMetadata(key);
|
|
795
|
+
this.metadata.set(key, computed(() => logic.compute(this.node.context)));
|
|
796
|
+
}
|
|
808
797
|
}
|
|
809
798
|
return this.metadata.get(key);
|
|
810
799
|
}
|
|
811
800
|
has(key) {
|
|
812
|
-
|
|
813
|
-
return this.node.logicNode.logic.hasAggregateMetadata(key);
|
|
814
|
-
} else {
|
|
815
|
-
return this.metadata.has(key);
|
|
816
|
-
}
|
|
801
|
+
return this.node.logicNode.logic.hasMetadata(key);
|
|
817
802
|
}
|
|
818
803
|
}
|
|
819
804
|
|
|
@@ -830,7 +815,10 @@ const FIELD_PROXY_HANDLER = {
|
|
|
830
815
|
return tgt.value().length;
|
|
831
816
|
}
|
|
832
817
|
if (p === Symbol.iterator) {
|
|
833
|
-
return
|
|
818
|
+
return () => {
|
|
819
|
+
tgt.value();
|
|
820
|
+
return Array.prototype[Symbol.iterator].apply(tgt.fieldProxy);
|
|
821
|
+
};
|
|
834
822
|
}
|
|
835
823
|
}
|
|
836
824
|
if (isObject(value)) {
|
|
@@ -885,6 +873,8 @@ function valueForWrite(sourceValue, newPropValue, prop) {
|
|
|
885
873
|
|
|
886
874
|
class FieldNodeStructure {
|
|
887
875
|
logic;
|
|
876
|
+
node;
|
|
877
|
+
createChildNode;
|
|
888
878
|
identitySymbol = Symbol();
|
|
889
879
|
_injector = undefined;
|
|
890
880
|
get injector() {
|
|
@@ -894,32 +884,146 @@ class FieldNodeStructure {
|
|
|
894
884
|
});
|
|
895
885
|
return this._injector;
|
|
896
886
|
}
|
|
897
|
-
constructor(logic) {
|
|
887
|
+
constructor(logic, node, createChildNode) {
|
|
898
888
|
this.logic = logic;
|
|
889
|
+
this.node = node;
|
|
890
|
+
this.createChildNode = createChildNode;
|
|
899
891
|
}
|
|
900
892
|
children() {
|
|
901
|
-
|
|
893
|
+
const map = this.childrenMap();
|
|
894
|
+
if (map === undefined) {
|
|
895
|
+
return [];
|
|
896
|
+
}
|
|
897
|
+
return Array.from(map.byPropertyKey.values()).map(child => untracked(child.reader));
|
|
902
898
|
}
|
|
903
899
|
getChild(key) {
|
|
900
|
+
const strKey = key.toString();
|
|
901
|
+
let reader = untracked(this.childrenMap)?.byPropertyKey.get(strKey)?.reader;
|
|
902
|
+
if (!reader) {
|
|
903
|
+
reader = this.createReader(strKey);
|
|
904
|
+
}
|
|
905
|
+
return reader();
|
|
906
|
+
}
|
|
907
|
+
reduceChildren(initialValue, fn, shortCircuit) {
|
|
904
908
|
const map = this.childrenMap();
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
return undefined;
|
|
909
|
+
if (!map) {
|
|
910
|
+
return initialValue;
|
|
908
911
|
}
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
if (
|
|
912
|
-
|
|
912
|
+
let value = initialValue;
|
|
913
|
+
for (const child of map.byPropertyKey.values()) {
|
|
914
|
+
if (shortCircuit?.(value)) {
|
|
915
|
+
break;
|
|
913
916
|
}
|
|
917
|
+
value = fn(untracked(child.reader), value);
|
|
914
918
|
}
|
|
915
|
-
return
|
|
919
|
+
return value;
|
|
916
920
|
}
|
|
917
921
|
destroy() {
|
|
918
922
|
this.injector.destroy();
|
|
919
923
|
}
|
|
924
|
+
createKeyInParent(options, identityInParent, initialKeyInParent) {
|
|
925
|
+
if (options.kind === 'root') {
|
|
926
|
+
return ROOT_KEY_IN_PARENT;
|
|
927
|
+
}
|
|
928
|
+
if (identityInParent === undefined) {
|
|
929
|
+
const key = initialKeyInParent;
|
|
930
|
+
return computed(() => {
|
|
931
|
+
if (this.parent.structure.getChild(key) !== this.node) {
|
|
932
|
+
throw new Error(`RuntimeError: orphan field, looking for property '${key}' of ${getDebugName(this.parent)}`);
|
|
933
|
+
}
|
|
934
|
+
return key;
|
|
935
|
+
});
|
|
936
|
+
} else {
|
|
937
|
+
let lastKnownKey = initialKeyInParent;
|
|
938
|
+
return computed(() => {
|
|
939
|
+
const parentValue = this.parent.structure.value();
|
|
940
|
+
if (!isArray(parentValue)) {
|
|
941
|
+
throw new Error(`RuntimeError: orphan field, expected ${getDebugName(this.parent)} to be an array`);
|
|
942
|
+
}
|
|
943
|
+
const data = parentValue[lastKnownKey];
|
|
944
|
+
if (isObject(data) && data.hasOwnProperty(this.parent.structure.identitySymbol) && data[this.parent.structure.identitySymbol] === identityInParent) {
|
|
945
|
+
return lastKnownKey;
|
|
946
|
+
}
|
|
947
|
+
for (let i = 0; i < parentValue.length; i++) {
|
|
948
|
+
const data = parentValue[i];
|
|
949
|
+
if (isObject(data) && data.hasOwnProperty(this.parent.structure.identitySymbol) && data[this.parent.structure.identitySymbol] === identityInParent) {
|
|
950
|
+
return lastKnownKey = i.toString();
|
|
951
|
+
}
|
|
952
|
+
}
|
|
953
|
+
throw new Error(`RuntimeError: orphan field, can't find element in array ${getDebugName(this.parent)}`);
|
|
954
|
+
});
|
|
955
|
+
}
|
|
956
|
+
}
|
|
957
|
+
createChildrenMap() {
|
|
958
|
+
return linkedSignal({
|
|
959
|
+
source: this.value,
|
|
960
|
+
computation: (value, previous) => {
|
|
961
|
+
if (!isObject(value)) {
|
|
962
|
+
return undefined;
|
|
963
|
+
}
|
|
964
|
+
const prevData = previous?.value ?? {
|
|
965
|
+
byPropertyKey: new Map()
|
|
966
|
+
};
|
|
967
|
+
let data;
|
|
968
|
+
const parentIsArray = isArray(value);
|
|
969
|
+
if (prevData !== undefined) {
|
|
970
|
+
if (parentIsArray) {
|
|
971
|
+
data = maybeRemoveStaleArrayFields(prevData, value, this.identitySymbol);
|
|
972
|
+
} else {
|
|
973
|
+
data = maybeRemoveStaleObjectFields(prevData, value);
|
|
974
|
+
}
|
|
975
|
+
}
|
|
976
|
+
for (const key of Object.keys(value)) {
|
|
977
|
+
let trackingKey = undefined;
|
|
978
|
+
const childValue = value[key];
|
|
979
|
+
if (childValue === undefined) {
|
|
980
|
+
if (prevData.byPropertyKey.has(key)) {
|
|
981
|
+
data ??= {
|
|
982
|
+
...prevData
|
|
983
|
+
};
|
|
984
|
+
data.byPropertyKey.delete(key);
|
|
985
|
+
}
|
|
986
|
+
continue;
|
|
987
|
+
}
|
|
988
|
+
if (parentIsArray && isObject(childValue) && !isArray(childValue)) {
|
|
989
|
+
trackingKey = childValue[this.identitySymbol] ??= Symbol(ngDevMode ? `id:${globalId++}` : '');
|
|
990
|
+
}
|
|
991
|
+
let childNode;
|
|
992
|
+
if (trackingKey) {
|
|
993
|
+
if (!prevData.byTrackingKey?.has(trackingKey)) {
|
|
994
|
+
data ??= {
|
|
995
|
+
...prevData
|
|
996
|
+
};
|
|
997
|
+
data.byTrackingKey ??= new Map();
|
|
998
|
+
data.byTrackingKey.set(trackingKey, this.createChildNode(key, trackingKey, parentIsArray));
|
|
999
|
+
}
|
|
1000
|
+
childNode = (data ?? prevData).byTrackingKey.get(trackingKey);
|
|
1001
|
+
}
|
|
1002
|
+
const child = prevData.byPropertyKey.get(key);
|
|
1003
|
+
if (child === undefined) {
|
|
1004
|
+
data ??= {
|
|
1005
|
+
...prevData
|
|
1006
|
+
};
|
|
1007
|
+
data.byPropertyKey.set(key, {
|
|
1008
|
+
reader: this.createReader(key),
|
|
1009
|
+
node: childNode ?? this.createChildNode(key, trackingKey, parentIsArray)
|
|
1010
|
+
});
|
|
1011
|
+
} else if (childNode && childNode !== child.node) {
|
|
1012
|
+
data ??= {
|
|
1013
|
+
...prevData
|
|
1014
|
+
};
|
|
1015
|
+
child.node = childNode;
|
|
1016
|
+
}
|
|
1017
|
+
}
|
|
1018
|
+
return data ?? prevData;
|
|
1019
|
+
}
|
|
1020
|
+
});
|
|
1021
|
+
}
|
|
1022
|
+
createReader(key) {
|
|
1023
|
+
return computed(() => this.childrenMap()?.byPropertyKey.get(key)?.node);
|
|
1024
|
+
}
|
|
920
1025
|
}
|
|
921
1026
|
class RootFieldNodeStructure extends FieldNodeStructure {
|
|
922
|
-
node;
|
|
923
1027
|
fieldManager;
|
|
924
1028
|
value;
|
|
925
1029
|
get parent() {
|
|
@@ -935,15 +1039,15 @@ class RootFieldNodeStructure extends FieldNodeStructure {
|
|
|
935
1039
|
return ROOT_KEY_IN_PARENT;
|
|
936
1040
|
}
|
|
937
1041
|
childrenMap;
|
|
938
|
-
constructor(node,
|
|
939
|
-
super(logic);
|
|
940
|
-
this.node = node;
|
|
1042
|
+
constructor(node, logic, fieldManager, value, createChildNode) {
|
|
1043
|
+
super(logic, node, createChildNode);
|
|
941
1044
|
this.fieldManager = fieldManager;
|
|
942
1045
|
this.value = value;
|
|
943
|
-
this.childrenMap =
|
|
1046
|
+
this.childrenMap = this.createChildrenMap();
|
|
944
1047
|
}
|
|
945
1048
|
}
|
|
946
1049
|
class ChildFieldNodeStructure extends FieldNodeStructure {
|
|
1050
|
+
logic;
|
|
947
1051
|
parent;
|
|
948
1052
|
root;
|
|
949
1053
|
pathKeys;
|
|
@@ -953,47 +1057,25 @@ class ChildFieldNodeStructure extends FieldNodeStructure {
|
|
|
953
1057
|
get fieldManager() {
|
|
954
1058
|
return this.root.structure.fieldManager;
|
|
955
1059
|
}
|
|
956
|
-
constructor(node,
|
|
957
|
-
super(logic);
|
|
1060
|
+
constructor(node, logic, parent, identityInParent, initialKeyInParent, createChildNode) {
|
|
1061
|
+
super(logic, node, createChildNode);
|
|
1062
|
+
this.logic = logic;
|
|
958
1063
|
this.parent = parent;
|
|
959
1064
|
this.root = this.parent.structure.root;
|
|
1065
|
+
this.keyInParent = this.createKeyInParent({
|
|
1066
|
+
kind: 'child',
|
|
1067
|
+
parent,
|
|
1068
|
+
pathNode: undefined,
|
|
1069
|
+
logic,
|
|
1070
|
+
initialKeyInParent,
|
|
1071
|
+
identityInParent,
|
|
1072
|
+
fieldAdapter: undefined
|
|
1073
|
+
}, identityInParent, initialKeyInParent);
|
|
960
1074
|
this.pathKeys = computed(() => [...parent.structure.pathKeys(), this.keyInParent()], ...(ngDevMode ? [{
|
|
961
1075
|
debugName: "pathKeys"
|
|
962
1076
|
}] : []));
|
|
963
|
-
if (identityInParent === undefined) {
|
|
964
|
-
const key = initialKeyInParent;
|
|
965
|
-
this.keyInParent = computed(() => {
|
|
966
|
-
if (parent.structure.childrenMap()?.get(key) !== node) {
|
|
967
|
-
throw new Error(`RuntimeError: orphan field, looking for property '${key}' of ${getDebugName(parent)}`);
|
|
968
|
-
}
|
|
969
|
-
return key;
|
|
970
|
-
}, ...(ngDevMode ? [{
|
|
971
|
-
debugName: "keyInParent"
|
|
972
|
-
}] : []));
|
|
973
|
-
} else {
|
|
974
|
-
let lastKnownKey = initialKeyInParent;
|
|
975
|
-
this.keyInParent = computed(() => {
|
|
976
|
-
const parentValue = parent.structure.value();
|
|
977
|
-
if (!isArray(parentValue)) {
|
|
978
|
-
throw new Error(`RuntimeError: orphan field, expected ${getDebugName(parent)} to be an array`);
|
|
979
|
-
}
|
|
980
|
-
const data = parentValue[lastKnownKey];
|
|
981
|
-
if (isObject(data) && data.hasOwnProperty(parent.structure.identitySymbol) && data[parent.structure.identitySymbol] === identityInParent) {
|
|
982
|
-
return lastKnownKey;
|
|
983
|
-
}
|
|
984
|
-
for (let i = 0; i < parentValue.length; i++) {
|
|
985
|
-
const data = parentValue[i];
|
|
986
|
-
if (isObject(data) && data.hasOwnProperty(parent.structure.identitySymbol) && data[parent.structure.identitySymbol] === identityInParent) {
|
|
987
|
-
return lastKnownKey = i.toString();
|
|
988
|
-
}
|
|
989
|
-
}
|
|
990
|
-
throw new Error(`RuntimeError: orphan field, can't find element in array ${getDebugName(parent)}`);
|
|
991
|
-
}, ...(ngDevMode ? [{
|
|
992
|
-
debugName: "keyInParent"
|
|
993
|
-
}] : []));
|
|
994
|
-
}
|
|
995
1077
|
this.value = deepSignal(this.parent.structure.value, this.keyInParent);
|
|
996
|
-
this.childrenMap =
|
|
1078
|
+
this.childrenMap = this.createChildrenMap();
|
|
997
1079
|
this.fieldManager.structures.add(this);
|
|
998
1080
|
}
|
|
999
1081
|
}
|
|
@@ -1006,80 +1088,50 @@ const ROOT_KEY_IN_PARENT = computed(() => {
|
|
|
1006
1088
|
}, ...(ngDevMode ? [{
|
|
1007
1089
|
debugName: "ROOT_KEY_IN_PARENT"
|
|
1008
1090
|
}] : []));
|
|
1009
|
-
function makeChildrenMapSignal(node, valueSignal, identitySymbol, pathNode, logic, adapter, createChildNode) {
|
|
1010
|
-
return linkedSignal({
|
|
1011
|
-
source: valueSignal,
|
|
1012
|
-
computation: (value, previous) => {
|
|
1013
|
-
let childrenMap = previous?.value;
|
|
1014
|
-
if (!isObject(value)) {
|
|
1015
|
-
return undefined;
|
|
1016
|
-
}
|
|
1017
|
-
const isValueArray = isArray(value);
|
|
1018
|
-
if (childrenMap !== undefined) {
|
|
1019
|
-
let oldKeys = undefined;
|
|
1020
|
-
if (isValueArray) {
|
|
1021
|
-
oldKeys = new Set(childrenMap.keys());
|
|
1022
|
-
for (let i = 0; i < value.length; i++) {
|
|
1023
|
-
const childValue = value[i];
|
|
1024
|
-
if (isObject(childValue) && childValue.hasOwnProperty(identitySymbol)) {
|
|
1025
|
-
oldKeys.delete(childValue[identitySymbol]);
|
|
1026
|
-
} else {
|
|
1027
|
-
oldKeys.delete(i.toString());
|
|
1028
|
-
}
|
|
1029
|
-
}
|
|
1030
|
-
for (const key of oldKeys) {
|
|
1031
|
-
childrenMap.delete(key);
|
|
1032
|
-
}
|
|
1033
|
-
} else {
|
|
1034
|
-
for (let key of childrenMap.keys()) {
|
|
1035
|
-
if (!value.hasOwnProperty(key)) {
|
|
1036
|
-
childrenMap.delete(key);
|
|
1037
|
-
}
|
|
1038
|
-
}
|
|
1039
|
-
}
|
|
1040
|
-
}
|
|
1041
|
-
for (let key of Object.keys(value)) {
|
|
1042
|
-
let trackingId = undefined;
|
|
1043
|
-
const childValue = value[key];
|
|
1044
|
-
if (childValue === undefined) {
|
|
1045
|
-
childrenMap?.delete(key);
|
|
1046
|
-
continue;
|
|
1047
|
-
}
|
|
1048
|
-
if (isValueArray && isObject(childValue) && !isArray(childValue)) {
|
|
1049
|
-
trackingId = childValue[identitySymbol] ??= Symbol(ngDevMode ? `id:${globalId++}` : '');
|
|
1050
|
-
}
|
|
1051
|
-
const identity = trackingId ?? key;
|
|
1052
|
-
if (childrenMap?.has(identity)) {
|
|
1053
|
-
continue;
|
|
1054
|
-
}
|
|
1055
|
-
let childPath;
|
|
1056
|
-
let childLogic;
|
|
1057
|
-
if (isValueArray) {
|
|
1058
|
-
childPath = pathNode.getChild(DYNAMIC);
|
|
1059
|
-
childLogic = logic.getChild(DYNAMIC);
|
|
1060
|
-
} else {
|
|
1061
|
-
childPath = pathNode.getChild(key);
|
|
1062
|
-
childLogic = logic.getChild(key);
|
|
1063
|
-
}
|
|
1064
|
-
childrenMap ??= new Map();
|
|
1065
|
-
childrenMap.set(identity, createChildNode({
|
|
1066
|
-
kind: 'child',
|
|
1067
|
-
parent: node,
|
|
1068
|
-
pathNode: childPath,
|
|
1069
|
-
logic: childLogic,
|
|
1070
|
-
initialKeyInParent: key,
|
|
1071
|
-
identityInParent: trackingId,
|
|
1072
|
-
fieldAdapter: adapter
|
|
1073
|
-
}));
|
|
1074
|
-
}
|
|
1075
|
-
return childrenMap;
|
|
1076
|
-
},
|
|
1077
|
-
equal: () => false
|
|
1078
|
-
});
|
|
1079
|
-
}
|
|
1080
1091
|
function getDebugName(node) {
|
|
1081
1092
|
return `<root>.${node.structure.pathKeys().join('.')}`;
|
|
1082
1093
|
}
|
|
1094
|
+
function maybeRemoveStaleArrayFields(prevData, value, identitySymbol) {
|
|
1095
|
+
let data;
|
|
1096
|
+
const oldKeys = new Set(prevData.byPropertyKey.keys());
|
|
1097
|
+
const oldTracking = new Set(prevData.byTrackingKey?.keys());
|
|
1098
|
+
for (let i = 0; i < value.length; i++) {
|
|
1099
|
+
const childValue = value[i];
|
|
1100
|
+
oldKeys.delete(i.toString());
|
|
1101
|
+
if (isObject(childValue) && childValue.hasOwnProperty(identitySymbol)) {
|
|
1102
|
+
oldTracking.delete(childValue[identitySymbol]);
|
|
1103
|
+
}
|
|
1104
|
+
}
|
|
1105
|
+
if (oldKeys.size > 0) {
|
|
1106
|
+
data ??= {
|
|
1107
|
+
...prevData
|
|
1108
|
+
};
|
|
1109
|
+
for (const key of oldKeys) {
|
|
1110
|
+
data.byPropertyKey.delete(key);
|
|
1111
|
+
}
|
|
1112
|
+
}
|
|
1113
|
+
if (oldTracking.size > 0) {
|
|
1114
|
+
data ??= {
|
|
1115
|
+
...prevData
|
|
1116
|
+
};
|
|
1117
|
+
for (const id of oldTracking) {
|
|
1118
|
+
data.byTrackingKey?.delete(id);
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
return data;
|
|
1122
|
+
}
|
|
1123
|
+
function maybeRemoveStaleObjectFields(prevData, value) {
|
|
1124
|
+
let data;
|
|
1125
|
+
for (const key of prevData.byPropertyKey.keys()) {
|
|
1126
|
+
if (!value.hasOwnProperty(key)) {
|
|
1127
|
+
data ??= {
|
|
1128
|
+
...prevData
|
|
1129
|
+
};
|
|
1130
|
+
data.byPropertyKey.delete(key);
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
return data;
|
|
1134
|
+
}
|
|
1083
1135
|
|
|
1084
1136
|
class FieldSubmitState {
|
|
1085
1137
|
node;
|
|
@@ -1116,7 +1168,9 @@ class FieldNode {
|
|
|
1116
1168
|
return this._context ??= new FieldNodeContext(this);
|
|
1117
1169
|
}
|
|
1118
1170
|
fieldProxy = new Proxy(() => this, FIELD_PROXY_HANDLER);
|
|
1171
|
+
pathNode;
|
|
1119
1172
|
constructor(options) {
|
|
1173
|
+
this.pathNode = options.pathNode;
|
|
1120
1174
|
this.fieldAdapter = options.fieldAdapter;
|
|
1121
1175
|
this.structure = this.fieldAdapter.createStructure(this, options);
|
|
1122
1176
|
this.validationState = this.fieldAdapter.createValidationState(this, options);
|
|
@@ -1191,26 +1245,23 @@ class FieldNode {
|
|
|
1191
1245
|
get name() {
|
|
1192
1246
|
return this.nodeState.name;
|
|
1193
1247
|
}
|
|
1194
|
-
metadataOrUndefined(key) {
|
|
1195
|
-
return this.hasMetadata(key) ? this.metadata(key) : undefined;
|
|
1196
|
-
}
|
|
1197
1248
|
get max() {
|
|
1198
|
-
return this.
|
|
1249
|
+
return this.metadata(MAX);
|
|
1199
1250
|
}
|
|
1200
1251
|
get maxLength() {
|
|
1201
|
-
return this.
|
|
1252
|
+
return this.metadata(MAX_LENGTH);
|
|
1202
1253
|
}
|
|
1203
1254
|
get min() {
|
|
1204
|
-
return this.
|
|
1255
|
+
return this.metadata(MIN);
|
|
1205
1256
|
}
|
|
1206
1257
|
get minLength() {
|
|
1207
|
-
return this.
|
|
1258
|
+
return this.metadata(MIN_LENGTH);
|
|
1208
1259
|
}
|
|
1209
1260
|
get pattern() {
|
|
1210
|
-
return this.
|
|
1261
|
+
return this.metadata(PATTERN) ?? EMPTY;
|
|
1211
1262
|
}
|
|
1212
1263
|
get required() {
|
|
1213
|
-
return this.
|
|
1264
|
+
return this.metadata(REQUIRED) ?? FALSE;
|
|
1214
1265
|
}
|
|
1215
1266
|
metadata(key) {
|
|
1216
1267
|
return this.metadataState.get(key);
|
|
@@ -1230,7 +1281,7 @@ class FieldNode {
|
|
|
1230
1281
|
untracked(() => this._reset(value));
|
|
1231
1282
|
}
|
|
1232
1283
|
_reset(value) {
|
|
1233
|
-
if (value) {
|
|
1284
|
+
if (value !== undefined) {
|
|
1234
1285
|
this.value.set(value);
|
|
1235
1286
|
}
|
|
1236
1287
|
this.nodeState.markAsUntouched();
|
|
@@ -1266,11 +1317,28 @@ class FieldNode {
|
|
|
1266
1317
|
static newRoot(fieldManager, value, pathNode, adapter) {
|
|
1267
1318
|
return adapter.newRoot(fieldManager, value, pathNode, adapter);
|
|
1268
1319
|
}
|
|
1269
|
-
static newChild(options) {
|
|
1270
|
-
return options.fieldAdapter.newChild(options);
|
|
1271
|
-
}
|
|
1272
1320
|
createStructure(options) {
|
|
1273
|
-
return options.kind === 'root' ? new RootFieldNodeStructure(this, options.
|
|
1321
|
+
return options.kind === 'root' ? new RootFieldNodeStructure(this, options.logic, options.fieldManager, options.value, this.newChild.bind(this)) : new ChildFieldNodeStructure(this, options.logic, options.parent, options.identityInParent, options.initialKeyInParent, this.newChild.bind(this));
|
|
1322
|
+
}
|
|
1323
|
+
newChild(key, trackingId, isArray) {
|
|
1324
|
+
let childPath;
|
|
1325
|
+
let childLogic;
|
|
1326
|
+
if (isArray) {
|
|
1327
|
+
childPath = this.pathNode.getChild(DYNAMIC);
|
|
1328
|
+
childLogic = this.structure.logic.getChild(DYNAMIC);
|
|
1329
|
+
} else {
|
|
1330
|
+
childPath = this.pathNode.getChild(key);
|
|
1331
|
+
childLogic = this.structure.logic.getChild(key);
|
|
1332
|
+
}
|
|
1333
|
+
return this.fieldAdapter.newChild({
|
|
1334
|
+
kind: 'child',
|
|
1335
|
+
parent: this,
|
|
1336
|
+
pathNode: childPath,
|
|
1337
|
+
logic: childLogic,
|
|
1338
|
+
initialKeyInParent: key,
|
|
1339
|
+
identityInParent: trackingId,
|
|
1340
|
+
fieldAdapter: this.fieldAdapter
|
|
1341
|
+
});
|
|
1274
1342
|
}
|
|
1275
1343
|
}
|
|
1276
1344
|
const EMPTY = computed(() => [], ...(ngDevMode ? [{
|
|
@@ -1308,13 +1376,13 @@ class FieldNodeState {
|
|
|
1308
1376
|
}
|
|
1309
1377
|
dirty = computed(() => {
|
|
1310
1378
|
const selfDirtyValue = this.selfDirty() && !this.isNonInteractive();
|
|
1311
|
-
return
|
|
1379
|
+
return this.node.structure.reduceChildren(selfDirtyValue, (child, value) => value || child.nodeState.dirty(), shortCircuitTrue);
|
|
1312
1380
|
}, ...(ngDevMode ? [{
|
|
1313
1381
|
debugName: "dirty"
|
|
1314
1382
|
}] : []));
|
|
1315
1383
|
touched = computed(() => {
|
|
1316
1384
|
const selfTouchedValue = this.selfTouched() && !this.isNonInteractive();
|
|
1317
|
-
return
|
|
1385
|
+
return this.node.structure.reduceChildren(selfTouchedValue, (child, value) => value || child.nodeState.touched(), shortCircuitTrue);
|
|
1318
1386
|
}, ...(ngDevMode ? [{
|
|
1319
1387
|
debugName: "touched"
|
|
1320
1388
|
}] : []));
|
|
@@ -1340,8 +1408,8 @@ class FieldNodeState {
|
|
|
1340
1408
|
debugName: "name"
|
|
1341
1409
|
}] : []));
|
|
1342
1410
|
debouncer = computed(() => {
|
|
1343
|
-
if (this.node.logicNode.logic.
|
|
1344
|
-
const debouncerLogic = this.node.logicNode.logic.
|
|
1411
|
+
if (this.node.logicNode.logic.hasMetadata(DEBOUNCER)) {
|
|
1412
|
+
const debouncerLogic = this.node.logicNode.logic.getMetadata(DEBOUNCER);
|
|
1345
1413
|
const debouncer = debouncerLogic.compute(this.node.context);
|
|
1346
1414
|
if (debouncer) {
|
|
1347
1415
|
return signal => debouncer(this.node.context, signal);
|
|
@@ -1506,5 +1574,5 @@ function markAllAsTouched(node) {
|
|
|
1506
1574
|
}
|
|
1507
1575
|
}
|
|
1508
1576
|
|
|
1509
|
-
export {
|
|
1577
|
+
export { BasicFieldAdapter, DEBOUNCER, FieldNode, FieldNodeState, FieldNodeStructure, FieldPathNode, MAX, MAX_LENGTH, MIN, MIN_LENGTH, MetadataKey, MetadataReducer, PATTERN, REQUIRED, addDefaultField, apply, applyEach, applyWhen, applyWhenValue, assertPathIsCurrent, calculateValidationSelfStatus, createManagedMetadataKey, createMetadataKey, form, getInjectorFromOptions, isArray, metadata, normalizeFormArgs, schema, submit };
|
|
1510
1578
|
//# sourceMappingURL=_structure-chunk.mjs.map
|