@angular/forms 21.1.0-next.0 → 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 +519 -527
- package/fesm2022/_structure-chunk.mjs.map +1 -1
- package/fesm2022/forms.mjs +163 -183
- package/fesm2022/forms.mjs.map +1 -1
- package/fesm2022/signals-compat.mjs +29 -40
- package/fesm2022/signals-compat.mjs.map +1 -1
- package/fesm2022/signals.mjs +283 -302
- package/fesm2022/signals.mjs.map +1 -1
- package/package.json +4 -4
- package/types/_structure-chunk.d.ts +802 -719
- package/types/forms.d.ts +1 -1
- package/types/signals-compat.d.ts +5 -4
- package/types/signals.d.ts +207 -241
|
@@ -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,157 +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
|
-
}, {
|
|
65
|
-
...(ngDevMode ? {
|
|
66
|
-
debugName: "rawSyncTreeErrors"
|
|
67
|
-
} : {})
|
|
68
|
-
});
|
|
69
|
-
syncErrors = computed(() => {
|
|
70
|
-
if (this.shouldSkipValidation()) {
|
|
71
|
-
return [];
|
|
72
|
-
}
|
|
73
|
-
return [...this.node.logicNode.logic.syncErrors.compute(this.node.context), ...this.syncTreeErrors(), ...normalizeErrors(this.node.submitState.serverErrors())];
|
|
74
|
-
}, {
|
|
75
|
-
...(ngDevMode ? {
|
|
76
|
-
debugName: "syncErrors"
|
|
77
|
-
} : {})
|
|
78
|
-
});
|
|
79
|
-
syncValid = computed(() => {
|
|
80
|
-
if (this.shouldSkipValidation()) {
|
|
81
|
-
return true;
|
|
82
|
-
}
|
|
83
|
-
return reduceChildren(this.node, this.syncErrors().length === 0, (child, value) => value && child.validationState.syncValid(), shortCircuitFalse);
|
|
84
|
-
}, {
|
|
85
|
-
...(ngDevMode ? {
|
|
86
|
-
debugName: "syncValid"
|
|
87
|
-
} : {})
|
|
88
|
-
});
|
|
89
|
-
syncTreeErrors = computed(() => this.rawSyncTreeErrors().filter(err => err.field === this.node.fieldProxy), {
|
|
90
|
-
...(ngDevMode ? {
|
|
91
|
-
debugName: "syncTreeErrors"
|
|
92
|
-
} : {})
|
|
93
|
-
});
|
|
94
|
-
rawAsyncErrors = computed(() => {
|
|
95
|
-
if (this.shouldSkipValidation()) {
|
|
96
|
-
return [];
|
|
97
|
-
}
|
|
98
|
-
return [...this.node.logicNode.logic.asyncErrors.compute(this.node.context), ...(this.node.structure.parent?.validationState.rawAsyncErrors() ?? [])];
|
|
99
|
-
}, {
|
|
100
|
-
...(ngDevMode ? {
|
|
101
|
-
debugName: "rawAsyncErrors"
|
|
102
|
-
} : {})
|
|
103
|
-
});
|
|
104
|
-
asyncErrors = computed(() => {
|
|
105
|
-
if (this.shouldSkipValidation()) {
|
|
106
|
-
return [];
|
|
107
|
-
}
|
|
108
|
-
return this.rawAsyncErrors().filter(err => err === 'pending' || err.field === this.node.fieldProxy);
|
|
109
|
-
}, {
|
|
110
|
-
...(ngDevMode ? {
|
|
111
|
-
debugName: "asyncErrors"
|
|
112
|
-
} : {})
|
|
113
|
-
});
|
|
114
|
-
errors = computed(() => [...this.syncErrors(), ...this.asyncErrors().filter(err => err !== 'pending')], {
|
|
115
|
-
...(ngDevMode ? {
|
|
116
|
-
debugName: "errors"
|
|
117
|
-
} : {})
|
|
118
|
-
});
|
|
119
|
-
errorSummary = computed(() => reduceChildren(this.node, this.errors(), (child, result) => [...result, ...child.errorSummary()]), {
|
|
120
|
-
...(ngDevMode ? {
|
|
121
|
-
debugName: "errorSummary"
|
|
122
|
-
} : {})
|
|
123
|
-
});
|
|
124
|
-
pending = computed(() => reduceChildren(this.node, this.asyncErrors().includes('pending'), (child, value) => value || child.validationState.asyncErrors().includes('pending')), {
|
|
125
|
-
...(ngDevMode ? {
|
|
126
|
-
debugName: "pending"
|
|
127
|
-
} : {})
|
|
128
|
-
});
|
|
129
|
-
status = computed(() => {
|
|
130
|
-
if (this.shouldSkipValidation()) {
|
|
131
|
-
return 'valid';
|
|
132
|
-
}
|
|
133
|
-
let ownStatus = calculateValidationSelfStatus(this);
|
|
134
|
-
return reduceChildren(this.node, ownStatus, (child, value) => {
|
|
135
|
-
if (value === 'invalid' || child.validationState.status() === 'invalid') {
|
|
136
|
-
return 'invalid';
|
|
137
|
-
} else if (value === 'unknown' || child.validationState.status() === 'unknown') {
|
|
138
|
-
return 'unknown';
|
|
139
|
-
}
|
|
140
|
-
return 'valid';
|
|
141
|
-
}, v => v === 'invalid');
|
|
142
|
-
}, {
|
|
143
|
-
...(ngDevMode ? {
|
|
144
|
-
debugName: "status"
|
|
145
|
-
} : {})
|
|
146
|
-
});
|
|
147
|
-
valid = computed(() => this.status() === 'valid', {
|
|
148
|
-
...(ngDevMode ? {
|
|
149
|
-
debugName: "valid"
|
|
150
|
-
} : {})
|
|
151
|
-
});
|
|
152
|
-
invalid = computed(() => this.status() === 'invalid', {
|
|
153
|
-
...(ngDevMode ? {
|
|
154
|
-
debugName: "invalid"
|
|
155
|
-
} : {})
|
|
156
|
-
});
|
|
157
|
-
shouldSkipValidation = computed(() => this.node.hidden() || this.node.disabled() || this.node.readonly(), {
|
|
158
|
-
...(ngDevMode ? {
|
|
159
|
-
debugName: "shouldSkipValidation"
|
|
160
|
-
} : {})
|
|
161
|
-
});
|
|
162
|
-
}
|
|
163
|
-
function normalizeErrors(error) {
|
|
164
|
-
if (error === undefined) {
|
|
165
|
-
return [];
|
|
166
|
-
}
|
|
167
|
-
if (isArray(error)) {
|
|
168
|
-
return error;
|
|
169
|
-
}
|
|
170
|
-
return [error];
|
|
171
|
-
}
|
|
172
|
-
function addDefaultField(errors, field) {
|
|
173
|
-
if (isArray(errors)) {
|
|
174
|
-
for (const error of errors) {
|
|
175
|
-
error.field ??= field;
|
|
176
|
-
}
|
|
177
|
-
} else if (errors) {
|
|
178
|
-
errors.field ??= field;
|
|
179
|
-
}
|
|
180
|
-
return errors;
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
let boundPathDepth = 0;
|
|
184
|
-
function getBoundPathDepth() {
|
|
185
|
-
return boundPathDepth;
|
|
39
|
+
function isArray(value) {
|
|
40
|
+
return Array.isArray(value);
|
|
186
41
|
}
|
|
187
|
-
function
|
|
188
|
-
return (
|
|
189
|
-
try {
|
|
190
|
-
boundPathDepth = depth;
|
|
191
|
-
return fn(...args);
|
|
192
|
-
} finally {
|
|
193
|
-
boundPathDepth = 0;
|
|
194
|
-
}
|
|
195
|
-
};
|
|
42
|
+
function isObject(value) {
|
|
43
|
+
return (typeof value === 'object' || typeof value === 'function') && value != null;
|
|
196
44
|
}
|
|
197
45
|
|
|
198
46
|
const DYNAMIC = Symbol();
|
|
@@ -255,10 +103,10 @@ class ArrayMergeLogic extends ArrayMergeIgnoreLogic {
|
|
|
255
103
|
super(predicates, undefined);
|
|
256
104
|
}
|
|
257
105
|
}
|
|
258
|
-
class
|
|
106
|
+
class MetadataMergeLogic extends AbstractLogic {
|
|
259
107
|
key;
|
|
260
108
|
get defaultValue() {
|
|
261
|
-
return this.key.getInitial();
|
|
109
|
+
return this.key.reducer.getInitial();
|
|
262
110
|
}
|
|
263
111
|
constructor(predicates, key) {
|
|
264
112
|
super(predicates);
|
|
@@ -266,13 +114,13 @@ class AggregateMetadataMergeLogic extends AbstractLogic {
|
|
|
266
114
|
}
|
|
267
115
|
compute(ctx) {
|
|
268
116
|
if (this.fns.length === 0) {
|
|
269
|
-
return this.key.getInitial();
|
|
117
|
+
return this.key.reducer.getInitial();
|
|
270
118
|
}
|
|
271
|
-
let acc = this.key.getInitial();
|
|
119
|
+
let acc = this.key.reducer.getInitial();
|
|
272
120
|
for (let i = 0; i < this.fns.length; i++) {
|
|
273
121
|
const item = this.fns[i](ctx);
|
|
274
122
|
if (item !== IGNORED) {
|
|
275
|
-
acc = this.key.reduce(acc, item);
|
|
123
|
+
acc = this.key.reducer.reduce(acc, item);
|
|
276
124
|
}
|
|
277
125
|
}
|
|
278
126
|
return acc;
|
|
@@ -304,8 +152,7 @@ class LogicContainer {
|
|
|
304
152
|
syncErrors;
|
|
305
153
|
syncTreeErrors;
|
|
306
154
|
asyncErrors;
|
|
307
|
-
|
|
308
|
-
metadataFactories = new Map();
|
|
155
|
+
metadata = new Map();
|
|
309
156
|
constructor(predicates) {
|
|
310
157
|
this.predicates = predicates;
|
|
311
158
|
this.hidden = new BooleanOrLogic(predicates);
|
|
@@ -315,26 +162,17 @@ class LogicContainer {
|
|
|
315
162
|
this.syncTreeErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
|
|
316
163
|
this.asyncErrors = ArrayMergeIgnoreLogic.ignoreNull(predicates);
|
|
317
164
|
}
|
|
318
|
-
|
|
319
|
-
return this.
|
|
320
|
-
}
|
|
321
|
-
getAggregateMetadataEntries() {
|
|
322
|
-
return this.aggregateMetadataKeys.entries();
|
|
165
|
+
hasMetadata(key) {
|
|
166
|
+
return this.metadata.has(key);
|
|
323
167
|
}
|
|
324
|
-
|
|
325
|
-
return this.
|
|
168
|
+
getMetadataKeys() {
|
|
169
|
+
return this.metadata.keys();
|
|
326
170
|
}
|
|
327
|
-
|
|
328
|
-
if (!this.
|
|
329
|
-
this.
|
|
330
|
-
}
|
|
331
|
-
return this.aggregateMetadataKeys.get(key);
|
|
332
|
-
}
|
|
333
|
-
addMetadataFactory(key, factory) {
|
|
334
|
-
if (this.metadataFactories.has(key)) {
|
|
335
|
-
throw new Error(`Can't define value twice for the same MetadataKey`);
|
|
171
|
+
getMetadata(key) {
|
|
172
|
+
if (!this.metadata.has(key)) {
|
|
173
|
+
this.metadata.set(key, new MetadataMergeLogic(this.predicates, key));
|
|
336
174
|
}
|
|
337
|
-
this.
|
|
175
|
+
return this.metadata.get(key);
|
|
338
176
|
}
|
|
339
177
|
mergeIn(other) {
|
|
340
178
|
this.hidden.mergeIn(other.hidden);
|
|
@@ -343,11 +181,9 @@ class LogicContainer {
|
|
|
343
181
|
this.syncErrors.mergeIn(other.syncErrors);
|
|
344
182
|
this.syncTreeErrors.mergeIn(other.syncTreeErrors);
|
|
345
183
|
this.asyncErrors.mergeIn(other.asyncErrors);
|
|
346
|
-
for (const
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
for (const [key, metadataFactory] of other.getMetadataFactoryEntries()) {
|
|
350
|
-
this.addMetadataFactory(key, metadataFactory);
|
|
184
|
+
for (const key of other.getMetadataKeys()) {
|
|
185
|
+
const metadataLogic = other.metadata.get(key);
|
|
186
|
+
this.getMetadata(key).mergeIn(metadataLogic);
|
|
351
187
|
}
|
|
352
188
|
}
|
|
353
189
|
}
|
|
@@ -385,11 +221,8 @@ class LogicNodeBuilder extends AbstractLogicNodeBuilder {
|
|
|
385
221
|
addAsyncErrorRule(logic) {
|
|
386
222
|
this.getCurrent().addAsyncErrorRule(logic);
|
|
387
223
|
}
|
|
388
|
-
|
|
389
|
-
this.getCurrent().
|
|
390
|
-
}
|
|
391
|
-
addMetadataFactory(key, factory) {
|
|
392
|
-
this.getCurrent().addMetadataFactory(key, factory);
|
|
224
|
+
addMetadataRule(key, logic) {
|
|
225
|
+
this.getCurrent().addMetadataRule(key, logic);
|
|
393
226
|
}
|
|
394
227
|
getChild(key) {
|
|
395
228
|
if (key === DYNAMIC) {
|
|
@@ -461,11 +294,8 @@ class NonMergeableLogicNodeBuilder extends AbstractLogicNodeBuilder {
|
|
|
461
294
|
addAsyncErrorRule(logic) {
|
|
462
295
|
this.logic.asyncErrors.push(setBoundPathDepthForResolution(logic, this.depth));
|
|
463
296
|
}
|
|
464
|
-
|
|
465
|
-
this.logic.
|
|
466
|
-
}
|
|
467
|
-
addMetadataFactory(key, factory) {
|
|
468
|
-
this.logic.addMetadataFactory(key, setBoundPathDepthForResolution(factory, this.depth));
|
|
297
|
+
addMetadataRule(key, logic) {
|
|
298
|
+
this.logic.getMetadata(key).push(setBoundPathDepthForResolution(logic, this.depth));
|
|
469
299
|
}
|
|
470
300
|
getChild(key) {
|
|
471
301
|
if (!this.children.has(key)) {
|
|
@@ -683,64 +513,196 @@ function assertPathIsCurrent(path) {
|
|
|
683
513
|
}
|
|
684
514
|
}
|
|
685
515
|
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
516
|
+
function metadata(path, key, logic) {
|
|
517
|
+
assertPathIsCurrent(path);
|
|
518
|
+
const pathNode = FieldPathNode.unwrapFieldPath(path);
|
|
519
|
+
pathNode.builder.addMetadataRule(key, logic);
|
|
520
|
+
return key;
|
|
689
521
|
}
|
|
690
|
-
|
|
691
|
-
|
|
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
|
+
};
|
|
692
570
|
}
|
|
693
|
-
class
|
|
694
|
-
|
|
695
|
-
|
|
571
|
+
class MetadataKey {
|
|
572
|
+
reducer;
|
|
573
|
+
create;
|
|
696
574
|
brand;
|
|
697
|
-
constructor(
|
|
698
|
-
this.
|
|
699
|
-
this.
|
|
575
|
+
constructor(reducer, create) {
|
|
576
|
+
this.reducer = reducer;
|
|
577
|
+
this.create = create;
|
|
700
578
|
}
|
|
701
579
|
}
|
|
702
|
-
function
|
|
703
|
-
return new
|
|
580
|
+
function createMetadataKey(reducer) {
|
|
581
|
+
return new MetadataKey(reducer ?? MetadataReducer.override());
|
|
582
|
+
}
|
|
583
|
+
function createManagedMetadataKey(create, reducer) {
|
|
584
|
+
return new MetadataKey(reducer ?? MetadataReducer.override(), create);
|
|
704
585
|
}
|
|
705
|
-
|
|
706
|
-
|
|
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';
|
|
707
601
|
}
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
602
|
+
class FieldValidationState {
|
|
603
|
+
node;
|
|
604
|
+
constructor(node) {
|
|
605
|
+
this.node = node;
|
|
606
|
+
}
|
|
607
|
+
rawSyncTreeErrors = computed(() => {
|
|
608
|
+
if (this.shouldSkipValidation()) {
|
|
609
|
+
return [];
|
|
610
|
+
}
|
|
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 [];
|
|
618
|
+
}
|
|
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;
|
|
712
626
|
}
|
|
713
|
-
|
|
714
|
-
|
|
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 [];
|
|
715
637
|
}
|
|
716
|
-
return
|
|
717
|
-
}, (
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
if (
|
|
722
|
-
return
|
|
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 [];
|
|
723
645
|
}
|
|
724
|
-
|
|
725
|
-
|
|
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';
|
|
726
662
|
}
|
|
727
|
-
|
|
728
|
-
|
|
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
|
+
}] : []));
|
|
729
684
|
}
|
|
730
|
-
function
|
|
731
|
-
|
|
685
|
+
function normalizeErrors(error) {
|
|
686
|
+
if (error === undefined) {
|
|
687
|
+
return [];
|
|
688
|
+
}
|
|
689
|
+
if (isArray(error)) {
|
|
690
|
+
return error;
|
|
691
|
+
}
|
|
692
|
+
return [error];
|
|
732
693
|
}
|
|
733
|
-
function
|
|
734
|
-
|
|
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;
|
|
735
703
|
}
|
|
736
|
-
const REQUIRED = orMetadataKey();
|
|
737
|
-
const MIN = maxMetadataKey();
|
|
738
|
-
const MAX = minMetadataKey();
|
|
739
|
-
const MIN_LENGTH = maxMetadataKey();
|
|
740
|
-
const MAX_LENGTH = minMetadataKey();
|
|
741
|
-
const PATTERN = listMetadataKey();
|
|
742
704
|
|
|
743
|
-
const DEBOUNCER =
|
|
705
|
+
const DEBOUNCER = createMetadataKey();
|
|
744
706
|
|
|
745
707
|
class FieldNodeContext {
|
|
746
708
|
node;
|
|
@@ -768,11 +730,9 @@ class FieldNodeContext {
|
|
|
768
730
|
}
|
|
769
731
|
}
|
|
770
732
|
return field.fieldProxy;
|
|
771
|
-
}, {
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
} : {})
|
|
775
|
-
});
|
|
733
|
+
}, ...(ngDevMode ? [{
|
|
734
|
+
debugName: "resolver"
|
|
735
|
+
}] : []));
|
|
776
736
|
this.cache.set(target, resolver);
|
|
777
737
|
}
|
|
778
738
|
return this.cache.get(target)();
|
|
@@ -798,11 +758,9 @@ class FieldNodeContext {
|
|
|
798
758
|
throw new Error(`RuntimeError: cannot access index, parent field is not an array`);
|
|
799
759
|
}
|
|
800
760
|
return Number(key);
|
|
801
|
-
}, {
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
} : {})
|
|
805
|
-
});
|
|
761
|
+
}, ...(ngDevMode ? [{
|
|
762
|
+
debugName: "index"
|
|
763
|
+
}] : []));
|
|
806
764
|
fieldTreeOf = p => this.resolve(p);
|
|
807
765
|
stateOf = p => this.resolve(p)();
|
|
808
766
|
valueOf = p => {
|
|
@@ -819,33 +777,28 @@ class FieldMetadataState {
|
|
|
819
777
|
metadata = new Map();
|
|
820
778
|
constructor(node) {
|
|
821
779
|
this.node = node;
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
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);
|
|
825
785
|
}
|
|
826
|
-
}
|
|
786
|
+
}
|
|
827
787
|
}
|
|
828
788
|
get(key) {
|
|
829
|
-
if (key
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
} : {})
|
|
838
|
-
});
|
|
839
|
-
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
|
+
}
|
|
840
797
|
}
|
|
841
798
|
return this.metadata.get(key);
|
|
842
799
|
}
|
|
843
800
|
has(key) {
|
|
844
|
-
|
|
845
|
-
return this.node.logicNode.logic.hasAggregateMetadata(key);
|
|
846
|
-
} else {
|
|
847
|
-
return this.metadata.has(key);
|
|
848
|
-
}
|
|
801
|
+
return this.node.logicNode.logic.hasMetadata(key);
|
|
849
802
|
}
|
|
850
803
|
}
|
|
851
804
|
|
|
@@ -862,7 +815,10 @@ const FIELD_PROXY_HANDLER = {
|
|
|
862
815
|
return tgt.value().length;
|
|
863
816
|
}
|
|
864
817
|
if (p === Symbol.iterator) {
|
|
865
|
-
return
|
|
818
|
+
return () => {
|
|
819
|
+
tgt.value();
|
|
820
|
+
return Array.prototype[Symbol.iterator].apply(tgt.fieldProxy);
|
|
821
|
+
};
|
|
866
822
|
}
|
|
867
823
|
}
|
|
868
824
|
if (isObject(value)) {
|
|
@@ -917,6 +873,8 @@ function valueForWrite(sourceValue, newPropValue, prop) {
|
|
|
917
873
|
|
|
918
874
|
class FieldNodeStructure {
|
|
919
875
|
logic;
|
|
876
|
+
node;
|
|
877
|
+
createChildNode;
|
|
920
878
|
identitySymbol = Symbol();
|
|
921
879
|
_injector = undefined;
|
|
922
880
|
get injector() {
|
|
@@ -926,32 +884,146 @@ class FieldNodeStructure {
|
|
|
926
884
|
});
|
|
927
885
|
return this._injector;
|
|
928
886
|
}
|
|
929
|
-
constructor(logic) {
|
|
887
|
+
constructor(logic, node, createChildNode) {
|
|
930
888
|
this.logic = logic;
|
|
889
|
+
this.node = node;
|
|
890
|
+
this.createChildNode = createChildNode;
|
|
931
891
|
}
|
|
932
892
|
children() {
|
|
933
|
-
|
|
893
|
+
const map = this.childrenMap();
|
|
894
|
+
if (map === undefined) {
|
|
895
|
+
return [];
|
|
896
|
+
}
|
|
897
|
+
return Array.from(map.byPropertyKey.values()).map(child => untracked(child.reader));
|
|
934
898
|
}
|
|
935
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) {
|
|
936
908
|
const map = this.childrenMap();
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
return undefined;
|
|
909
|
+
if (!map) {
|
|
910
|
+
return initialValue;
|
|
940
911
|
}
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
if (
|
|
944
|
-
|
|
912
|
+
let value = initialValue;
|
|
913
|
+
for (const child of map.byPropertyKey.values()) {
|
|
914
|
+
if (shortCircuit?.(value)) {
|
|
915
|
+
break;
|
|
945
916
|
}
|
|
917
|
+
value = fn(untracked(child.reader), value);
|
|
946
918
|
}
|
|
947
|
-
return
|
|
919
|
+
return value;
|
|
948
920
|
}
|
|
949
921
|
destroy() {
|
|
950
922
|
this.injector.destroy();
|
|
951
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
|
+
}
|
|
952
1025
|
}
|
|
953
1026
|
class RootFieldNodeStructure extends FieldNodeStructure {
|
|
954
|
-
node;
|
|
955
1027
|
fieldManager;
|
|
956
1028
|
value;
|
|
957
1029
|
get parent() {
|
|
@@ -967,15 +1039,15 @@ class RootFieldNodeStructure extends FieldNodeStructure {
|
|
|
967
1039
|
return ROOT_KEY_IN_PARENT;
|
|
968
1040
|
}
|
|
969
1041
|
childrenMap;
|
|
970
|
-
constructor(node,
|
|
971
|
-
super(logic);
|
|
972
|
-
this.node = node;
|
|
1042
|
+
constructor(node, logic, fieldManager, value, createChildNode) {
|
|
1043
|
+
super(logic, node, createChildNode);
|
|
973
1044
|
this.fieldManager = fieldManager;
|
|
974
1045
|
this.value = value;
|
|
975
|
-
this.childrenMap =
|
|
1046
|
+
this.childrenMap = this.createChildrenMap();
|
|
976
1047
|
}
|
|
977
1048
|
}
|
|
978
1049
|
class ChildFieldNodeStructure extends FieldNodeStructure {
|
|
1050
|
+
logic;
|
|
979
1051
|
parent;
|
|
980
1052
|
root;
|
|
981
1053
|
pathKeys;
|
|
@@ -985,151 +1057,87 @@ class ChildFieldNodeStructure extends FieldNodeStructure {
|
|
|
985
1057
|
get fieldManager() {
|
|
986
1058
|
return this.root.structure.fieldManager;
|
|
987
1059
|
}
|
|
988
|
-
constructor(node,
|
|
989
|
-
super(logic);
|
|
1060
|
+
constructor(node, logic, parent, identityInParent, initialKeyInParent, createChildNode) {
|
|
1061
|
+
super(logic, node, createChildNode);
|
|
1062
|
+
this.logic = logic;
|
|
990
1063
|
this.parent = parent;
|
|
991
1064
|
this.root = this.parent.structure.root;
|
|
992
|
-
this.
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
}, {
|
|
1005
|
-
...(ngDevMode ? {
|
|
1006
|
-
debugName: "keyInParent"
|
|
1007
|
-
} : {})
|
|
1008
|
-
});
|
|
1009
|
-
} else {
|
|
1010
|
-
let lastKnownKey = initialKeyInParent;
|
|
1011
|
-
this.keyInParent = computed(() => {
|
|
1012
|
-
const parentValue = parent.structure.value();
|
|
1013
|
-
if (!isArray(parentValue)) {
|
|
1014
|
-
throw new Error(`RuntimeError: orphan field, expected ${getDebugName(parent)} to be an array`);
|
|
1015
|
-
}
|
|
1016
|
-
const data = parentValue[lastKnownKey];
|
|
1017
|
-
if (isObject(data) && data.hasOwnProperty(parent.structure.identitySymbol) && data[parent.structure.identitySymbol] === identityInParent) {
|
|
1018
|
-
return lastKnownKey;
|
|
1019
|
-
}
|
|
1020
|
-
for (let i = 0; i < parentValue.length; i++) {
|
|
1021
|
-
const data = parentValue[i];
|
|
1022
|
-
if (isObject(data) && data.hasOwnProperty(parent.structure.identitySymbol) && data[parent.structure.identitySymbol] === identityInParent) {
|
|
1023
|
-
return lastKnownKey = i.toString();
|
|
1024
|
-
}
|
|
1025
|
-
}
|
|
1026
|
-
throw new Error(`RuntimeError: orphan field, can't find element in array ${getDebugName(parent)}`);
|
|
1027
|
-
}, {
|
|
1028
|
-
...(ngDevMode ? {
|
|
1029
|
-
debugName: "keyInParent"
|
|
1030
|
-
} : {})
|
|
1031
|
-
});
|
|
1032
|
-
}
|
|
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);
|
|
1074
|
+
this.pathKeys = computed(() => [...parent.structure.pathKeys(), this.keyInParent()], ...(ngDevMode ? [{
|
|
1075
|
+
debugName: "pathKeys"
|
|
1076
|
+
}] : []));
|
|
1033
1077
|
this.value = deepSignal(this.parent.structure.value, this.keyInParent);
|
|
1034
|
-
this.childrenMap =
|
|
1078
|
+
this.childrenMap = this.createChildrenMap();
|
|
1035
1079
|
this.fieldManager.structures.add(this);
|
|
1036
1080
|
}
|
|
1037
1081
|
}
|
|
1038
1082
|
let globalId = 0;
|
|
1039
|
-
const ROOT_PATH_KEYS = computed(() => [], {
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
} : {})
|
|
1043
|
-
});
|
|
1083
|
+
const ROOT_PATH_KEYS = computed(() => [], ...(ngDevMode ? [{
|
|
1084
|
+
debugName: "ROOT_PATH_KEYS"
|
|
1085
|
+
}] : []));
|
|
1044
1086
|
const ROOT_KEY_IN_PARENT = computed(() => {
|
|
1045
1087
|
throw new Error(`RuntimeError: the top-level field in the form has no parent`);
|
|
1046
|
-
}, {
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
} : {})
|
|
1050
|
-
});
|
|
1051
|
-
function makeChildrenMapSignal(node, valueSignal, identitySymbol, pathNode, logic, adapter, createChildNode) {
|
|
1052
|
-
return linkedSignal({
|
|
1053
|
-
source: valueSignal,
|
|
1054
|
-
computation: (value, previous) => {
|
|
1055
|
-
let childrenMap = previous?.value;
|
|
1056
|
-
if (!isObject(value)) {
|
|
1057
|
-
return undefined;
|
|
1058
|
-
}
|
|
1059
|
-
const isValueArray = isArray(value);
|
|
1060
|
-
if (childrenMap !== undefined) {
|
|
1061
|
-
let oldKeys = undefined;
|
|
1062
|
-
if (isValueArray) {
|
|
1063
|
-
oldKeys = new Set(childrenMap.keys());
|
|
1064
|
-
for (let i = 0; i < value.length; i++) {
|
|
1065
|
-
const childValue = value[i];
|
|
1066
|
-
if (isObject(childValue) && childValue.hasOwnProperty(identitySymbol)) {
|
|
1067
|
-
oldKeys.delete(childValue[identitySymbol]);
|
|
1068
|
-
} else {
|
|
1069
|
-
oldKeys.delete(i.toString());
|
|
1070
|
-
}
|
|
1071
|
-
}
|
|
1072
|
-
for (const key of oldKeys) {
|
|
1073
|
-
childrenMap.delete(key);
|
|
1074
|
-
}
|
|
1075
|
-
} else {
|
|
1076
|
-
for (let key of childrenMap.keys()) {
|
|
1077
|
-
if (!value.hasOwnProperty(key)) {
|
|
1078
|
-
childrenMap.delete(key);
|
|
1079
|
-
}
|
|
1080
|
-
}
|
|
1081
|
-
}
|
|
1082
|
-
}
|
|
1083
|
-
for (let key of Object.keys(value)) {
|
|
1084
|
-
let trackingId = undefined;
|
|
1085
|
-
const childValue = value[key];
|
|
1086
|
-
if (childValue === undefined) {
|
|
1087
|
-
childrenMap?.delete(key);
|
|
1088
|
-
continue;
|
|
1089
|
-
}
|
|
1090
|
-
if (isValueArray && isObject(childValue) && !isArray(childValue)) {
|
|
1091
|
-
trackingId = childValue[identitySymbol] ??= Symbol(ngDevMode ? `id:${globalId++}` : '');
|
|
1092
|
-
}
|
|
1093
|
-
const identity = trackingId ?? key;
|
|
1094
|
-
if (childrenMap?.has(identity)) {
|
|
1095
|
-
continue;
|
|
1096
|
-
}
|
|
1097
|
-
let childPath;
|
|
1098
|
-
let childLogic;
|
|
1099
|
-
if (isValueArray) {
|
|
1100
|
-
childPath = pathNode.getChild(DYNAMIC);
|
|
1101
|
-
childLogic = logic.getChild(DYNAMIC);
|
|
1102
|
-
} else {
|
|
1103
|
-
childPath = pathNode.getChild(key);
|
|
1104
|
-
childLogic = logic.getChild(key);
|
|
1105
|
-
}
|
|
1106
|
-
childrenMap ??= new Map();
|
|
1107
|
-
childrenMap.set(identity, createChildNode({
|
|
1108
|
-
kind: 'child',
|
|
1109
|
-
parent: node,
|
|
1110
|
-
pathNode: childPath,
|
|
1111
|
-
logic: childLogic,
|
|
1112
|
-
initialKeyInParent: key,
|
|
1113
|
-
identityInParent: trackingId,
|
|
1114
|
-
fieldAdapter: adapter
|
|
1115
|
-
}));
|
|
1116
|
-
}
|
|
1117
|
-
return childrenMap;
|
|
1118
|
-
},
|
|
1119
|
-
equal: () => false
|
|
1120
|
-
});
|
|
1121
|
-
}
|
|
1088
|
+
}, ...(ngDevMode ? [{
|
|
1089
|
+
debugName: "ROOT_KEY_IN_PARENT"
|
|
1090
|
+
}] : []));
|
|
1122
1091
|
function getDebugName(node) {
|
|
1123
1092
|
return `<root>.${node.structure.pathKeys().join('.')}`;
|
|
1124
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
|
+
}
|
|
1125
1135
|
|
|
1126
1136
|
class FieldSubmitState {
|
|
1127
1137
|
node;
|
|
1128
|
-
selfSubmitting = signal(false, {
|
|
1129
|
-
|
|
1130
|
-
|
|
1131
|
-
} : {})
|
|
1132
|
-
});
|
|
1138
|
+
selfSubmitting = signal(false, ...(ngDevMode ? [{
|
|
1139
|
+
debugName: "selfSubmitting"
|
|
1140
|
+
}] : []));
|
|
1133
1141
|
serverErrors;
|
|
1134
1142
|
constructor(node) {
|
|
1135
1143
|
this.node = node;
|
|
@@ -1143,11 +1151,9 @@ class FieldSubmitState {
|
|
|
1143
1151
|
}
|
|
1144
1152
|
submitting = computed(() => {
|
|
1145
1153
|
return this.selfSubmitting() || (this.node.structure.parent?.submitting() ?? false);
|
|
1146
|
-
}, {
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
} : {})
|
|
1150
|
-
});
|
|
1154
|
+
}, ...(ngDevMode ? [{
|
|
1155
|
+
debugName: "submitting"
|
|
1156
|
+
}] : []));
|
|
1151
1157
|
}
|
|
1152
1158
|
|
|
1153
1159
|
class FieldNode {
|
|
@@ -1162,7 +1168,9 @@ class FieldNode {
|
|
|
1162
1168
|
return this._context ??= new FieldNodeContext(this);
|
|
1163
1169
|
}
|
|
1164
1170
|
fieldProxy = new Proxy(() => this, FIELD_PROXY_HANDLER);
|
|
1171
|
+
pathNode;
|
|
1165
1172
|
constructor(options) {
|
|
1173
|
+
this.pathNode = options.pathNode;
|
|
1166
1174
|
this.fieldAdapter = options.fieldAdapter;
|
|
1167
1175
|
this.structure = this.fieldAdapter.createStructure(this, options);
|
|
1168
1176
|
this.validationState = this.fieldAdapter.createValidationState(this, options);
|
|
@@ -1186,11 +1194,9 @@ class FieldNode {
|
|
|
1186
1194
|
get value() {
|
|
1187
1195
|
return this.structure.value;
|
|
1188
1196
|
}
|
|
1189
|
-
_controlValue = linkedSignal(() => this.value(), {
|
|
1190
|
-
|
|
1191
|
-
|
|
1192
|
-
} : {})
|
|
1193
|
-
});
|
|
1197
|
+
_controlValue = linkedSignal(() => this.value(), ...(ngDevMode ? [{
|
|
1198
|
+
debugName: "_controlValue"
|
|
1199
|
+
}] : []));
|
|
1194
1200
|
get controlValue() {
|
|
1195
1201
|
return this._controlValue.asReadonly();
|
|
1196
1202
|
}
|
|
@@ -1239,26 +1245,23 @@ class FieldNode {
|
|
|
1239
1245
|
get name() {
|
|
1240
1246
|
return this.nodeState.name;
|
|
1241
1247
|
}
|
|
1242
|
-
metadataOrUndefined(key) {
|
|
1243
|
-
return this.hasMetadata(key) ? this.metadata(key) : undefined;
|
|
1244
|
-
}
|
|
1245
1248
|
get max() {
|
|
1246
|
-
return this.
|
|
1249
|
+
return this.metadata(MAX);
|
|
1247
1250
|
}
|
|
1248
1251
|
get maxLength() {
|
|
1249
|
-
return this.
|
|
1252
|
+
return this.metadata(MAX_LENGTH);
|
|
1250
1253
|
}
|
|
1251
1254
|
get min() {
|
|
1252
|
-
return this.
|
|
1255
|
+
return this.metadata(MIN);
|
|
1253
1256
|
}
|
|
1254
1257
|
get minLength() {
|
|
1255
|
-
return this.
|
|
1258
|
+
return this.metadata(MIN_LENGTH);
|
|
1256
1259
|
}
|
|
1257
1260
|
get pattern() {
|
|
1258
|
-
return this.
|
|
1261
|
+
return this.metadata(PATTERN) ?? EMPTY;
|
|
1259
1262
|
}
|
|
1260
1263
|
get required() {
|
|
1261
|
-
return this.
|
|
1264
|
+
return this.metadata(REQUIRED) ?? FALSE;
|
|
1262
1265
|
}
|
|
1263
1266
|
metadata(key) {
|
|
1264
1267
|
return this.metadataState.get(key);
|
|
@@ -1278,7 +1281,7 @@ class FieldNode {
|
|
|
1278
1281
|
untracked(() => this._reset(value));
|
|
1279
1282
|
}
|
|
1280
1283
|
_reset(value) {
|
|
1281
|
-
if (value) {
|
|
1284
|
+
if (value !== undefined) {
|
|
1282
1285
|
this.value.set(value);
|
|
1283
1286
|
}
|
|
1284
1287
|
this.nodeState.markAsUntouched();
|
|
@@ -1314,36 +1317,45 @@ class FieldNode {
|
|
|
1314
1317
|
static newRoot(fieldManager, value, pathNode, adapter) {
|
|
1315
1318
|
return adapter.newRoot(fieldManager, value, pathNode, adapter);
|
|
1316
1319
|
}
|
|
1317
|
-
static newChild(options) {
|
|
1318
|
-
return options.fieldAdapter.newChild(options);
|
|
1319
|
-
}
|
|
1320
1320
|
createStructure(options) {
|
|
1321
|
-
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
|
+
});
|
|
1322
1342
|
}
|
|
1323
1343
|
}
|
|
1324
|
-
const EMPTY = computed(() => [], {
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
...(ngDevMode ? {
|
|
1331
|
-
debugName: "FALSE"
|
|
1332
|
-
} : {})
|
|
1333
|
-
});
|
|
1344
|
+
const EMPTY = computed(() => [], ...(ngDevMode ? [{
|
|
1345
|
+
debugName: "EMPTY"
|
|
1346
|
+
}] : []));
|
|
1347
|
+
const FALSE = computed(() => false, ...(ngDevMode ? [{
|
|
1348
|
+
debugName: "FALSE"
|
|
1349
|
+
}] : []));
|
|
1334
1350
|
|
|
1335
1351
|
class FieldNodeState {
|
|
1336
1352
|
node;
|
|
1337
|
-
selfTouched = signal(false, {
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
...(ngDevMode ? {
|
|
1344
|
-
debugName: "selfDirty"
|
|
1345
|
-
} : {})
|
|
1346
|
-
});
|
|
1353
|
+
selfTouched = signal(false, ...(ngDevMode ? [{
|
|
1354
|
+
debugName: "selfTouched"
|
|
1355
|
+
}] : []));
|
|
1356
|
+
selfDirty = signal(false, ...(ngDevMode ? [{
|
|
1357
|
+
debugName: "selfDirty"
|
|
1358
|
+
}] : []));
|
|
1347
1359
|
markAsTouched() {
|
|
1348
1360
|
this.selfTouched.set(true);
|
|
1349
1361
|
}
|
|
@@ -1356,80 +1368,60 @@ class FieldNodeState {
|
|
|
1356
1368
|
markAsUntouched() {
|
|
1357
1369
|
this.selfTouched.set(false);
|
|
1358
1370
|
}
|
|
1359
|
-
fieldBindings = signal([], {
|
|
1360
|
-
|
|
1361
|
-
|
|
1362
|
-
} : {})
|
|
1363
|
-
});
|
|
1371
|
+
fieldBindings = signal([], ...(ngDevMode ? [{
|
|
1372
|
+
debugName: "fieldBindings"
|
|
1373
|
+
}] : []));
|
|
1364
1374
|
constructor(node) {
|
|
1365
1375
|
this.node = node;
|
|
1366
1376
|
}
|
|
1367
1377
|
dirty = computed(() => {
|
|
1368
1378
|
const selfDirtyValue = this.selfDirty() && !this.isNonInteractive();
|
|
1369
|
-
return
|
|
1370
|
-
}, {
|
|
1371
|
-
|
|
1372
|
-
|
|
1373
|
-
} : {})
|
|
1374
|
-
});
|
|
1379
|
+
return this.node.structure.reduceChildren(selfDirtyValue, (child, value) => value || child.nodeState.dirty(), shortCircuitTrue);
|
|
1380
|
+
}, ...(ngDevMode ? [{
|
|
1381
|
+
debugName: "dirty"
|
|
1382
|
+
}] : []));
|
|
1375
1383
|
touched = computed(() => {
|
|
1376
1384
|
const selfTouchedValue = this.selfTouched() && !this.isNonInteractive();
|
|
1377
|
-
return
|
|
1378
|
-
}, {
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
|
|
1392
|
-
});
|
|
1393
|
-
readonly = computed(() => (this.node.structure.parent?.nodeState.readonly() || this.node.logicNode.logic.readonly.compute(this.node.context)) ?? false, {
|
|
1394
|
-
...(ngDevMode ? {
|
|
1395
|
-
debugName: "readonly"
|
|
1396
|
-
} : {})
|
|
1397
|
-
});
|
|
1398
|
-
hidden = computed(() => (this.node.structure.parent?.nodeState.hidden() || this.node.logicNode.logic.hidden.compute(this.node.context)) ?? false, {
|
|
1399
|
-
...(ngDevMode ? {
|
|
1400
|
-
debugName: "hidden"
|
|
1401
|
-
} : {})
|
|
1402
|
-
});
|
|
1385
|
+
return this.node.structure.reduceChildren(selfTouchedValue, (child, value) => value || child.nodeState.touched(), shortCircuitTrue);
|
|
1386
|
+
}, ...(ngDevMode ? [{
|
|
1387
|
+
debugName: "touched"
|
|
1388
|
+
}] : []));
|
|
1389
|
+
disabledReasons = computed(() => [...(this.node.structure.parent?.nodeState.disabledReasons() ?? []), ...this.node.logicNode.logic.disabledReasons.compute(this.node.context)], ...(ngDevMode ? [{
|
|
1390
|
+
debugName: "disabledReasons"
|
|
1391
|
+
}] : []));
|
|
1392
|
+
disabled = computed(() => !!this.disabledReasons().length, ...(ngDevMode ? [{
|
|
1393
|
+
debugName: "disabled"
|
|
1394
|
+
}] : []));
|
|
1395
|
+
readonly = computed(() => (this.node.structure.parent?.nodeState.readonly() || this.node.logicNode.logic.readonly.compute(this.node.context)) ?? false, ...(ngDevMode ? [{
|
|
1396
|
+
debugName: "readonly"
|
|
1397
|
+
}] : []));
|
|
1398
|
+
hidden = computed(() => (this.node.structure.parent?.nodeState.hidden() || this.node.logicNode.logic.hidden.compute(this.node.context)) ?? false, ...(ngDevMode ? [{
|
|
1399
|
+
debugName: "hidden"
|
|
1400
|
+
}] : []));
|
|
1403
1401
|
name = computed(() => {
|
|
1404
1402
|
const parent = this.node.structure.parent;
|
|
1405
1403
|
if (!parent) {
|
|
1406
1404
|
return this.node.structure.fieldManager.rootName;
|
|
1407
1405
|
}
|
|
1408
1406
|
return `${parent.name()}.${this.node.structure.keyInParent()}`;
|
|
1409
|
-
}, {
|
|
1410
|
-
|
|
1411
|
-
|
|
1412
|
-
} : {})
|
|
1413
|
-
});
|
|
1407
|
+
}, ...(ngDevMode ? [{
|
|
1408
|
+
debugName: "name"
|
|
1409
|
+
}] : []));
|
|
1414
1410
|
debouncer = computed(() => {
|
|
1415
|
-
if (this.node.logicNode.logic.
|
|
1416
|
-
const debouncerLogic = this.node.logicNode.logic.
|
|
1411
|
+
if (this.node.logicNode.logic.hasMetadata(DEBOUNCER)) {
|
|
1412
|
+
const debouncerLogic = this.node.logicNode.logic.getMetadata(DEBOUNCER);
|
|
1417
1413
|
const debouncer = debouncerLogic.compute(this.node.context);
|
|
1418
1414
|
if (debouncer) {
|
|
1419
1415
|
return signal => debouncer(this.node.context, signal);
|
|
1420
1416
|
}
|
|
1421
1417
|
}
|
|
1422
1418
|
return this.node.structure.parent?.nodeState.debouncer?.();
|
|
1423
|
-
}, {
|
|
1424
|
-
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
...(ngDevMode ? {
|
|
1430
|
-
debugName: "isNonInteractive"
|
|
1431
|
-
} : {})
|
|
1432
|
-
});
|
|
1419
|
+
}, ...(ngDevMode ? [{
|
|
1420
|
+
debugName: "debouncer"
|
|
1421
|
+
}] : []));
|
|
1422
|
+
isNonInteractive = computed(() => this.hidden() || this.disabled() || this.readonly(), ...(ngDevMode ? [{
|
|
1423
|
+
debugName: "isNonInteractive"
|
|
1424
|
+
}] : []));
|
|
1433
1425
|
}
|
|
1434
1426
|
|
|
1435
1427
|
class BasicFieldAdapter {
|
|
@@ -1582,5 +1574,5 @@ function markAllAsTouched(node) {
|
|
|
1582
1574
|
}
|
|
1583
1575
|
}
|
|
1584
1576
|
|
|
1585
|
-
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 };
|
|
1586
1578
|
//# sourceMappingURL=_structure-chunk.mjs.map
|