Optional callbacks for handleSubmit #668
-
I don't know if this is a common use case, but I sometimes have multiple buttons with a form that each have a different submit action. A simple change that I think accomplishes this is optional parameters for handleSubmit handleSubmit = async (
onSubmit?: (props: {
value: TFormData
formApi: FormApi<TFormData, TFormValidator>
}) => any | Promise<any>
onSubmitInvalid?: (props: {
value: TFormData
formApi: FormApi<TFormData, TFormValidator>
}) => void) {
onSubmit ??= this.options.onSubmit
onSubmitInvalid ??= this.options.onSubmitInvalid
// replace options handlers with local handlers Then I could call handleSubmit with different callbacks on the different buttons. |
Beta Was this translation helpful? Give feedback.
Replies: 3 comments 2 replies
-
I don't think this logic should live in TanStack Form to handle multiple button presses. You can do this rather trivially otherwise with individual functions in your codebase outside of Form, right?
|
Beta Was this translation helpful? Give feedback.
-
Thanks for the response. This is how I would do it now. It's not too bad, but does feel a little odd/too much for something simple. But I could foresee issues with the async timing on it if I was not careful to only allow one option to handle at a time. Maybe there is a better way to do this and I am missing something. import type { FieldApi } from '@tanstack/react-form';
import { useForm } from '@tanstack/react-form';
import * as React from 'react';
import { createRoot } from 'react-dom/client';
function FieldInfo({ field }: { field: FieldApi<any, any, any, any> }) {
return (
<>
{field.state.meta.touchedErrors ? (
<em>{field.state.meta.touchedErrors}</em>
) : null}
{field.state.meta.isValidating ? 'Validating...' : null}
</>
);
}
export default function App() {
const form = useForm({
defaultValues: {
firstName: '',
lastName: '',
},
onSubmit: async ({ value }) => {
if (flag.current === 1) {
submitToApi1({ value });
}
if (flag.current === 2) {
submitToApi2({ value });
}
},
});
const flag = React.useRef(1);
function submitToApi1({ value }) {
alert('Api 1');
}
function submitToApi2({ value }) {
alert('Api 2');
}
return (
<div>
<h1>Simple Form Example</h1>
<form
onSubmit={(e) => {
e.preventDefault();
e.stopPropagation();
// form.handleSubmit();
}}
>
<div>
{/* A type-safe field component*/}
<form.Field
name="firstName"
validators={{
onChange: ({ value }) =>
!value
? 'A first name is required'
: value.length < 3
? 'First name must be at least 3 characters'
: undefined,
onChangeAsyncDebounceMs: 500,
onChangeAsync: async ({ value }) => {
await new Promise((resolve) => setTimeout(resolve, 1000));
return (
value.includes('error') && 'No "error" allowed in first name'
);
},
}}
children={(field) => {
// Avoid hasty abstractions. Render props are great!
return (
<>
<label htmlFor={field.name}>First Name:</label>
<input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
);
}}
/>
</div>
<div>
<form.Field
name="lastName"
children={(field) => (
<>
<label htmlFor={field.name}>Last Name:</label>
<input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<FieldInfo field={field} />
</>
)}
/>
</div>
<button
onClick={() => {
flag.current = 1;
form.handleSubmit();
}}
>
Submit to Api 1
</button>
<button
onClick={() => {
flag.current = 2;
form.handleSubmit();
}}
>
Submit to Api 2
</button>
</form>
</div>
);
}
const rootElement = document.getElementById('root')!;
createRoot(rootElement).render(<App />); What I would like to be able to do. <button
onClick={() => {
form.handleSubmit(submitToApi1);
}}
>
Submit to Api 1
</button>
<button
onClick={() => {
form.handleSubmit(submitToApi2);
}}
>
Submit to Api 2
</button> |
Beta Was this translation helpful? Give feedback.
-
@crutchcorn we have a similar case and introducing a ref just for passing a parameter seems to be an anti-pattern. Could handleSubmit not just return the form values? That seems to align with the overall API design and allows for such a callback. |
Beta Was this translation helpful? Give feedback.
I don't think this logic should live in TanStack Form to handle multiple button presses. You can do this rather trivially otherwise with individual functions in your codebase outside of Form, right?