T
TanStack2w ago
foreign-sapphire

child forms with multi-steps

Hello, I'm looking to build a big form with a bunch of image upload in the middle of the form. let's say: - input type=text - input type=file - input type=text - input type=file - input type=submit i would like to have the type=file to handle display locally until the form is submitted, for which, i'd like each type=file to submit separately and in advance, then when all images have been submitted to the BE, use their uploadId in the form submission. for the last part, i already know how to do. i'll make an isolated component which will have uploadId: string, onChange: (newUploadId: string) => void as interface. where i'm lost is how to orchestrate the "child submissions" at the call of form.handleSubmit. I was thinking that child forms would allow this, but i'm not really sure how to build it. any guidance would be appreciated.
12 Replies
flat-fuchsia
flat-fuchsia2w ago
so that call needs to succeed before the submission continues. Would the form validators.onSubmitAsync be a good spot for it?
foreign-sapphire
foreign-sapphireOP2w ago
@Luca | LeCarbonator thanks for your answer 😄 i'm not so sure if validators.onSubmitAsync would do. i mean, maybe it could, but is the validator api meant to do that? also, it has to be in the flow of the main form's submission ; so if the main form has validation issue (let's assume the 3rd text input), it should not have uploaded the 1st image (which is in 2nd position)
flat-fuchsia
flat-fuchsia2w ago
On form.handleSubmit, here's the call order: Only goes to the next one after a success validators. - onChange - onChangeAsync - onBlur - onBlurAsync - onSubmit - onSubmitAsync All succeeded -> onSubmit
foreign-sapphire
foreign-sapphireOP2w ago
so far i have no choice but to be outside of the form api. i'm passing a callback fn in the input files which register themselves to the parent form, and 1st thing in form.onSubmit is to call those fns and manually set returned values in the backend payload.
flat-fuchsia
flat-fuchsia2w ago
so onSubmitAsync is the last hurdle before onSubmit
foreign-sapphire
foreign-sapphireOP2w ago
that's what i thought. so it would call the 2nd validator.onSubmitAsync before the 3rd validator, which means my 1st image would upload even tho the form might not pass validation afterwards.
flat-fuchsia
flat-fuchsia2w ago
so you're using field-level validators?
foreign-sapphire
foreign-sapphireOP2w ago
yes, with <form.Field validators={{ onSubmit: zodShape }} /> (as you previously taught me 🙏) i was hoping there would be a hook in the field api which would allow last minute transformation of the value before passing to the form's onSubmit (and that would be async) something in the vibe of: <form.Field beforeSubmit={async (value, field) => doSomething()} /> (and maybe afterSubmit would be nice to replace local b64 image src to uploaded url, that kind of post-submit field/input level transformation)
flat-fuchsia
flat-fuchsia2w ago
it's not a thing yet, no
foreign-sapphire
foreign-sapphireOP2w ago
as said as for now what i do is roughly
const uploadFns = useRef<
Record<string, () => Promise<[id: string, url: string]>
>({})

const form = useForm({
defaultValues: {
image1: '',
image2: '',
},
async onSubmit({ value }) {
const replacements = Object.fromEntries(
await Promise.all(uploadFns.current)
)

await callBackend({ ...value, ...replacements })
}
})

<form.Field name="image1">
{(field) => (
<FileInput
id="image1"
registerUploadFn={(fn) => uploadFns.current["image1"] = fn}
/>
)
</form.Field>
const uploadFns = useRef<
Record<string, () => Promise<[id: string, url: string]>
>({})

const form = useForm({
defaultValues: {
image1: '',
image2: '',
},
async onSubmit({ value }) {
const replacements = Object.fromEntries(
await Promise.all(uploadFns.current)
)

await callBackend({ ...value, ...replacements })
}
})

<form.Field name="image1">
{(field) => (
<FileInput
id="image1"
registerUploadFn={(fn) => uploadFns.current["image1"] = fn}
/>
)
</form.Field>
it looks "not that bad" in that example but when a form is a bit more complicated, it starts to smell
flat-fuchsia
flat-fuchsia2w ago
yeah, makes sense. Say, what happens if one of the file uploads fail? Like the last one? does it undo the other ones?
foreign-sapphire
foreign-sapphireOP6d ago
mmm sadly no once it's uploaded... 🤷 @Luca | LeCarbonator that being said i can implement a delete if uploaded too

Did you find this page helpful?