| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
`markAsTouched()` synchronized a pending debounced value only on the field it was called on. Its descendants were marked as touched, but their pending values stayed unsynced. `submit()` marks the root as touched before running the action, so submitting with Enter while a debounced child still had focus ran the action with the child's old value. Clicking a submit button hid the bug, because the click blurs the input first. Flush each descendant's pending value as it is marked as touched. Tested with new specs in `//packages/forms/signals/test/node:test` that fail without the fix: one touches the root, the other calls `submit()`. Fixes angular#71149
There was a problem hiding this comment.
AGENT: Great catch on syncing pending values when a field is touched!
However, there is an inconsistency introduced by putting child.flushSync() directly in the descendant loop. If a child control skips validation (for example, if it's hidden or disabled), child.markAsTouchedInternal() will return early and will not iterate over its own descendants. Because of the unconditional child.flushSync() in the parent's loop, this results in:
To fix this inconsistency and fulfill the goal of flushing exactly when a node is marked as touched, we can move this.flushSync() directly into markAsTouchedInternal() right after marking the state, and remove the manual flush from the markAsTouched wrapper.
Here is what that would look like:
markAsTouched(options?: MarkAsTouchedOptions): void {
if (this.structure.isOrphaned()) {
return;
}
untracked(() => {
this.markAsTouchedInternal(options);
// Removed this.flushSync() here
});
}
markAsTouchedInternal(options?: MarkAsTouchedOptions): void {
if (this.structure.isOrphaned()) {
return;
}
if (this.validationState.shouldSkipValidation()) {
return; // Hidden/Disabled fields correctly bail out BEFORE flushing
}
this.nodeState.markAsTouched();
this.flushSync(); // Flush happens EXACTLY when marked as touched
if (options?.skipDescendants) {
return;
}
for (const child of this.structure.children()) {
child.markAsTouchedInternal();
// Removed child.flushSync() here
}
}This ensures that hidden/disabled fields (and their descendants) correctly bail out before flushing, keeping the tree consistent.
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
markAsTouched() synchronized a pending debounced value only on the field it was called on. Its descendants were marked as touched, but their pending values stayed unsynced.
submit() marks the root as touched before running the action, so submitting with Enter while a debounced child still had focus ran the action with the child's old value. Clicking a submit button hid the bug, because the click blurs the input first.
Flush each descendant's pending value as it is marked as touched.
Tested with new specs in //packages/forms/signals/test/node:test that fail without the fix: one touches the root, the other calls submit().
Fixes #71149