Array subfields missing errors in fieldMeta
Describe the bug
When a user pushes a field using field.pushValue or form.pushFieldValue, errors for the subfields are missing from fieldMeta.
This leads to a really bad state if the new subfield has errors on the form level schema. canSubmit becomes false so they can't submit the form, yet the error cannot be surfaced.
Your minimal, reproducible example
https://stackblitz.com/edit/tanstack-form-lntbeysv?file=src%2Findex.tsx
Steps to reproduce
- Add a row
- Notice canSubmit is now false, yet no error is surfaced
- Click "Log all errors" notice that the form has the errors, but is missing from the fieldMeta
Expected behavior
In the UI, I would expect the error is immediately surfaced to the user.
How often does this bug happen?
Every time
Screenshots or Videos
No response
Platform
See StackBlitz, latest version of TSF, valid TS version
TanStack Form adapter
react-form
TanStack Form version
^1.7.0
TypeScript version
No response
Additional context
This happens because we run the validator before the new pushed subfields mount. Since they have not mounted fieldMeta does not exist leading to the difference between the errorMap on the form and field level.
I propose that onMount we always check if the form errorMap contains errors for the field. If so, copy it over.
@juanvilladev could you do me a massive favour? can you try this again with the latest version... theres a slight chance my latest commit might have fixed this as a side effect.
A very slight chance, but a slight chance at that... if not I'll have to investigate š
[edit] Just checked it myself, unfortunately not
Hey, I wanted to ask what the status of the problem is, the error still exists and we can not display error messages on the arrays. (tested with 1.14.2)
Iām also running into this same issue and am curious if there are any updates?
If someone would be so kind to check the unit test I've wrote is testing for the expected behaviour, that would be a massive help to getting this fixed.
I'm on holiday atm so getting some conformation before starting the fix would be super appreciated š.
I believe I am also seeing this issue if a form is validated before the FieldApi instance mounts in the DOM, regardless of explicit pushFieldValue behavior.
In my use case, certain form fields are rendered in a Tab Panel that is not mounted unless the user click on the Tab. The form still validates successfully and the unmounted field errors are present in the FormApi's error state as expected.
If the user then clicks on the Tab and the Tab Panel that contains the invalid fields is rendered, the FieldApi instances mount but they do not derive their FieldMeta from any existing FormApi state.
So the same de-sync issue arises where a field has errors in the FormApi error state but the FieldMeta does not reflect any issue.
I'm running into the same problem. Is there an update yet?
I also have this problem, which was quite the headache to figure out. Our application has multi-tab sections: Some fields are multilingual so we want the user to supply translations in all languages. I am trying to mark panel buttons as 'contains an issue' but sadly the field's meta does not exist until the panel is opened.
As a workaround, what would be the best way to programmatically 'mount' a field?
I am currently solving the problem with useField({ form, name }) which seems to create the FieldApi for every field you use it for:
/**
* In multi-tab forms or forms where not all fields are visibile / have mounted UI,
* the unmounted fields have no field meta and thus no error state on submit.
* Tanstack form does not sync form-level errors to fields when they later get mounted, so those fields do not contain earlier errors.
* Also, when we would want to check/count errors in a unrendered tab, we cannot loop over these fields' meta until the tab has been opened.
* Solution:
* We force-mount the fields by using useField. This ensures that the fields are always mounted and have errors in their meta.
* Todo: reevaluate this once tanstack syncs form-level errors to unmounted fields
* https://github.com/TanStack/form/issues/1630
* https://github.com/TanStack/form/issues/1460
*/
function FieldEnsurer({ form, name }: { form: AnyFormApi; name: string }) {
useField({ form, name });
return null;
}
Then, where I render the tab-row containing fields for each language, I do:
{
// Force mount all fields to ensure they have errors in their meta
}
{languages.map((language) =>
getFieldKeysForLanguage(language).map((key) => (
<FieldEnsurer key={key} form={form} name={key} />
)),
)}
<TranslationEditor.TabsList>
{languages.map((language) => {
return (
<form.Subscribe
key={language}
selector={({ fieldMeta }) =>
getFieldKeysForLanguage(language).some(
(key) => fieldMeta[key]?.errors?.length,
)
}
children={(hasErrorsInLanguage) => {
return (
<TranslationEditor.TabTrigger
key={language}
language={language}
error={hasErrorsInLanguage}
/>
);
}}
/>
);
})}
</TranslationEditor.TabsList>