-
Notifications
You must be signed in to change notification settings - Fork 963
fix(form): propagate dirty and touched fields to parent form #5566
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. Weβll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: v4
Are you sure you want to change the base?
fix(form): propagate dirty and touched fields to parent form #5566
Conversation
commit: |
| // Propagate dirty and touched fields to parent form | ||
| if ((event.type === 'change' || event.type === 'input' || event.type === 'focus' || event.type === 'blur') && parentBus) { | ||
| parentBus.emit(event) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| parentBus.emit(event) | |
| const eventToPropagate = props.name ? { ...event, name: props.name as any } : event | |
| parentBus.emit(eventToPropagate) |
Event field names from nested forms are not properly scoped when propagated to the parent, causing incorrect entries in parent form's dirtyFields and touchedFields sets.
View Details
Analysis
Nested form events not properly scoped when propagated to parent form
What fails: Nested form field names are not prefixed with the nested form's path when propagating input events to the parent form, causing unscoped field names to be added to parent form's dirtyFields, touchedFields, and blurredFields sets, creating type mismatches and inconsistency with how errors are handled.
How to reproduce:
- Create a parent form with schema containing a nested object field, e.g.,
{ email: string, address: { street: string } } - Render a nested Form component with
name="address"and schema{ street: string } - User types in the nested "street" input field
- Check
parentForm.dirtyFields- it contains'street'instead of'address'
Example fixture in test/components/fixtures/FormNested.vue shows this pattern where parent has a nested form at name="nested" with a field "field". When user modifies this nested field, the parent's dirtyFields receives 'field' instead of 'nested'.
What happens vs expected behavior:
Current behavior:
- Nested form's useFormField emits event:
{ type: 'change', name: 'street' } - Nested form receives it, correctly adds
'street'to its own dirtyFields - Nested form propagates to parent WITHOUT scoping:
parentBus.emit({ type: 'change', name: 'street' }) - Parent receives
{ type: 'change', name: 'street' }and adds'street'to parent's dirtyFields - Result: Parent dirtyFields contains invalid key
'street'(should be'address'or'nested')
Expected behavior:
- Nested form should scope the event name to its own path before propagating
- Event propagated to parent should be:
{ type: 'change', name: 'address' } - Parent should add
'address'(valid key) to its dirtyFields
Type signature shows the issue:
const dirtyFields: Set<keyof I> = reactive(new Set<keyof I>())
// where I = InferInput<S>
// For parent form, this should only contain valid keys from parent schema like 'email' | 'address'Root cause: Lines 167-169 in src/runtime/components/Form.vue emit events to parent without modifying the field name. When errors are handled (line 226), addFormPath() is used to prefix error names with the nested form's path. The same scoping should be applied to field name events.
Why it's a bug:
- Type mismatch:
dirtyFieldsdeclared asSet<keyof I>will contain invalid keys - Inconsistency: Error paths ARE scoped using
addFormPath(), but event names are NOT - API contract violation: Form.dirtyFields should only contain keys that exist in the form's schema
- Developers checking
form.dirtyFieldssee nested field names instead of top-level field names, breaking abstraction
Reference: See Form type definition at src/runtime/types/form.ts line 18 which specifies dirtyFields: ReadonlySet<DeepReadonly<keyof FormData<S, false>>> - only valid schema keys.
π Linked issue
Resolves #5144
β Type of change
π Description
If current form component has a parent form, emit
'input','change','focus'or'blur'via the parent form event bus.Prior to this change,
dirtyFieldsandtouchedFieldsdidn't take into accountnestedForms.π Checklist