form.setFieldValue doesn't trigger validation
I noticed that calling form.setFieldValue("field-name", myvalue) doesn't trigger validation. Looking at the code, similar methods, like pushFieldValue, call form.validateField() after updating the value. That doesn't happen in setFieldValue().
setFieldValue is meant for programmatically setting a field value, while pushFieldValue is an array specifically meant to handle change (like field.handleChange).
Could you provide a reproducible example of where the validation from setFieldValue is required / desired?
I can see reasoning for both not forcing validation and forcing validation. It's possible to add it as option parameter like the dontUpdateMeta prop, but I'd like to know what the use case is first.
In my situation, I have a file input and I want to implement the logic for handling file changes outside of JSX for better readability. I cannot access field.handleChange outside the form.Field component unless I pass it to my handlePictureChange function. I found that form.setFieldValue is the closest alternative I could use, and I expected it to behave similarly to field.handleChange. It took me some time to realize why changing the file doesn't trigger validation.
In my opinion, form.setFieldValue should trigger validation by default, with an option like dontValidate available to disable it if needed. I don't understand why someone would want to change a field value programmatically without triggering validation. If the user has set up a validator, it should always be respected by default.
import { useState, type ChangeEvent } from "react";
import { useForm } from "@tanstack/react-form";
import { z } from "zod/v4-mini";
const schema = z.object({
profilePicture: z.optional(z.file().check(z.maxSize(2_000_000))),
});
function ProfileForm() {
const [avatarPreview, setAvatarPreview] = useState<string>();
const form = useForm({
defaultValues: { profilePicture: undefined } as {
profilePicture: File | undefined;
},
validators: {
onChange: schema,
},
});
async function handlePictureChange(e: ChangeEvent<HTMLInputElement>) {
const file = e.target.files?.[0];
if (file) {
form.setFieldValue("profilePicture", file);
const reader = new FileReader();
reader.onload = () => {
setAvatarPreview(reader.result as string);
};
reader.readAsDataURL(file);
}
}
return (
<form
onSubmit={async (e) => {
e.preventDefault();
await form.handleSubmit();
}}
>
<form.Field name="profilePicture">
{(_field) => (
<input
type="file"
accept="image/jpeg, image/png"
onChange={handlePictureChange}
/>
)}
</form.Field>
</form>
);
}
@amirhhashemi The closest alternative you can use is to pass the output of handleFieldChange to the updater parameter of field.handleChange. Something like:
import { useState, type ChangeEvent } from "react";
import { useForm } from "@tanstack/react-form";
import { z } from "zod/v4-mini";
const schema = z.object({
profilePicture: z.optional(z.file().check(z.maxSize(2_000_000))),
});
function ProfileForm() {
const [avatarPreview, setAvatarPreview] = useState<string>();
const form = useForm({
defaultValues: { profilePicture: undefined } as {
profilePicture: File | undefined;
},
validators: {
onChange: schema,
},
});
function handlePictureChange(e: ChangeEvent<HTMLInputElement>): File | undefined {
const file = e.target.files?.[0];
if (file) {
const reader = new FileReader();
reader.onload = () => {
setAvatarPreview(reader.result as string);
};
reader.readAsDataURL(file);
}
return file;
}
return (
<form
onSubmit={async (e) => {
e.preventDefault();
await form.handleSubmit();
}}
>
<form.Field name="profilePicture">
{(field) => (
<input
type="file"
accept="image/jpeg, image/png"
onChange={(e) => field.handleChange(handlePictureChange(e))}
/>
)}
</form.Field>
</form>
);
}
Providing a property as shorthand may be worth looking into, but as for now, you can manually call form.validateField programmatically right after setFieldValue which allows for the same level of control as an option parameter.
field.handleChange will remain the intended way to trigger validation and listeners either way, and in your code snippet, that can be achieved while extracting the callback.
Hi, did you find a solution to this?
I have the exact same issue. It should run the validation, but it doesn't! It's very frustrating! I can't figure out a way to deal with this.
@LeCarbonator Thank you. Your solution worked for me. However, I still believe this could pose a problem. While I can't think of a specific use case, the existence of a method called form.setFieldValue that can be called from anywhere carries the risk that users might forget to trigger validation manually, allowing unvalidated data to be submitted. It should not be easy to bypass validation. If setFieldValue is not meant to trigger validation, it should at least be documented clearly.
@2Bros-MX
@LeCarbonator Thank you. Your solution worked for me. However, I still believe this could pose a problem. While I can't think of a specific use case, the existence of a method called
form.setFieldValuethat can be called from anywhere carries the risk that users might forget to trigger validation manually, allowing unvalidated data to be submitted. It should not be easy to bypass validation. IfsetFieldValueis not meant to trigger validation, it should at least be documented clearly.
That is a fair point. I think I've changed my mind about the situation.
Hi!
To add to the discussion, I would also like to mention that form.setFieldValue doesn't trigger the form's listeners.onChange either
Do we think that it should?
Thank you 🙂
@LeCarbonator Thank you. Your solution worked for me. However, I still believe this could pose a problem. While I can't think of a specific use case, the existence of a method called
form.setFieldValuethat can be called from anywhere carries the risk that users might forget to trigger validation manually, allowing unvalidated data to be submitted. It should not be easy to bypass validation. IfsetFieldValueis not meant to trigger validation, it should at least be documented clearly.That is a fair point. I think I've changed my mind about the situation.
I also expected form.setFieldValue to trigger respective onChange and onChangeListenTo validators. Looking forward to the future update where this is added, thank you for your work on this amazing lib!
Hi!
To add to the discussion, I would also like to mention that
form.setFieldValuedoesn't trigger the form'slisteners.onChangeeitherDo we think that it should?
Thank you 🙂
I agree that it should!
+1 Any update about this one?
Any updated on this issue 👀 ?
What we ended up doing was creating a utility function like this:
export function setFieldValue<
TFormData,
TOnMount extends undefined | FormValidateOrFn<TFormData>,
TOnChange extends undefined | FormValidateOrFn<TFormData>,
TOnChangeAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnBlur extends undefined | FormValidateOrFn<TFormData>,
TOnBlurAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnSubmit extends undefined | FormValidateOrFn<TFormData>,
TOnSubmitAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnDynamic extends undefined | FormValidateOrFn<TFormData>,
TOnDynamicAsync extends undefined | FormAsyncValidateOrFn<TFormData>,
TOnServer extends undefined | FormAsyncValidateOrFn<TFormData>,
TSubmitMeta,
TField extends DeepKeys<TFormData>,
>(
form: ReactFormExtendedApi<
TFormData,
TOnMount,
TOnChange,
TOnChangeAsync,
TOnBlur,
TOnBlurAsync,
TOnSubmit,
TOnSubmitAsync,
TOnDynamic,
TOnDynamicAsync,
TOnServer,
TSubmitMeta
>,
field: TField,
value: Updater<DeepValue<TFormData, TField>>,
) {
form.resetField(field);
form.setFieldValue(field, value);
}
And using canSubmitWhenInvalid: true on the form. It fixes our specific case (onSubmit validation errors not clearing when values are set with form.setFieldValue()), but probably won't work for all cases.
Would still love an update re: this issue though
I'd appreciate it if you could install the PR version to test this functionality. You can find the script in the PR reply
Here's the script for React, pulled from that reply:
npm i https://pkg.pr.new/@tanstack/react-form@1680
I'd appreciate it if you could install the PR version to test this functionality. You can find the script in the PR reply
Here's the script for React, pulled from that reply:
npm i https://pkg.pr.new/@tanstack/react-form@1680
I tested this and I am seeing listeners being triggered. I only have a form onChangeAsync no field level validations so I can't verify the validators are being triggered since the validation is running anyway because the field I changed. But I can tell you the listeners sure are working now and they were not on the version I was using 1.19.x or something.
I documented my setup / use case in the PR you have open.