Field Array Validation Not Refreshing Properly When Field is Removed
wscullen opened this issue · comments
Describe the bug
When multiple fields are added to a field array, and there is validation errors, if you update one of these fields to not have a validation error, and remove a field with a validation error (i - 1 to the good field), the removed field's validation error is applied to the field that does not have validation errors. It seems as though validation (or form state) is not properly re-evaluated and updated when a field is removed from a field array. Due to this bug, a call to form.validateAllFields("change") was attempted as a work around, but this results in the following error:
@tanstack_react-form.js?v=4b8d5915:1011 Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'errorMap')
at @tanstack_react-form…?v=4b8d5915:1011:25
at functionalUpdate (@tanstack_react-form…s?v=4b8d5915:303:42)
at @tanstack_react-form…s?v=4b8d5915:753:22
at Store.setState (@tanstack_react-form…?v=4b8d5915:274:118)
at FormApi.setFieldMeta (@tanstack_react-form…s?v=4b8d5915:748:18)
at FieldApi.setMeta (@tanstack_react-form…s?v=4b8d5915:986:43)
at @tanstack_react-form…?v=4b8d5915:1008:18
at Store.batch (@tanstack_react-form.js?v=4b8d5915:292:7)
at FieldApi.validateSync (@tanstack_react-form…s?v=4b8d5915:995:23)
at FieldApi.validate (@tanstack_react-form…?v=4b8d5915:1106:35)
blitz.810981ba.js:352
To view this error in the linked example project, uncomment out the indicated line 63 in the Form component.
Your minimal, reproducible example
https://stackblitz.com/edit/vitejs-vite-81fflp?file=src%2Fcomponents%2FForm.tsx
Steps to reproduce
- Add three people fields to the field array
- Click Submit to trigger validation
- Change the 3rd person's name to a valid value (any string), the validation error for that field will go away
- Remove the 2nd person from the field array by clicking the X
Result is the 2nd person (which was the 3rd person) now has the validation error showing of the previously deleted 2nd person.
To see the error, call form.validateAllFields("change") immediately after removing the field from the field array.
Expected behavior
I expect to see all validation for the 2nd person (previously the 3rd person) to continue to not have any errors, instead I'm seeing the previous validation error for the original 2nd person (which was removed).
When trying to work around the issue by manually revalidating all fields with form.validateAllFields("change") after the field is removed, errors are thrown (see above). This error can be avoided if the form.validateAllFields("change") call is placed in a setTimeout.
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
macOS 12.7.2
chrome Version 122.0.6261.129 (Official Build) (arm64)
TanStack Form adapter
react-form
TanStack Form version
v0.16.0
TypeScript version
5.2.2
Additional context
No response
Looks like we have a bug here, I'll check it out later this week!
@crutchcorn You worked a lot on array fields, so I'll summon you to ask for help! 😆
If you check the video recording below, there are subfields in form.fieldMeta
:
"people[0].name"
"people[1].name"
When we delete "people[0].name"
, the values in form.values
are updated properly, but the meta data in form.fieldMeta
do not, because "people[0].name"
stays the same (instead of getting the value of "people[1].name"
), and "people[1].name"
simply gets deleted.
Kapture.2024-03-24.at.22.07.36.mp4
I could dig deeper, but I thought maybe you could give me some pointers here since you've worked with array fields recently.
@fulopkovacs do you think this is in part due to this? #662
@fulopkovacs do you think this is in part due to this? #662
They might be related, but I tested the PR of the supposed fix for #662 (#700), and it seems like it does not solve the issue.
I'll look into it! (Thanks to #656, I'm much more comfortable with working on validation-related issues 🤣 )
Ok, I found the bug and made a fix locally, I will try to clean it up and commit it this week.
The main source of the problem is that the array field is not re-validated after one of its subfields gets removed. But, here are some interesting things that I found when I was investigating the issue:
- calling
validate()
on the array field itself did not re-validate the subfields (not sure if it's by accident or design), so I tried usingvalidateAllFields()
to quickly get the job done validateAllFields()
didn't work, because thefieldInfo
property ofFormApi
still contained data related to the deleted field, andvalidateAllFields()
relies on it to get the fields that should be validated- another fun fact: since the
removeValue()
method ofFieldApi
doesn't have anopts
arg ({touch: boolean}
), it can't pass it tothis.form.removeFieldValue
, which prevents the array field's meta data from being updated (it should happen here, it's fixed in #701 )
The fix I have locally deletes the data related to the last subfield from this.fieldInfo
in removeFieldValue()
before calling validateAllFields
. This way we don't have errors and everything gets updated properly.