T
TanStackβ€’14mo ago
stormy-gold

Trigger onChange only on dirty fields

Is it possible to only trigger the onChange validation after the field is dirty ?
I want the validation to first occur when the user leaves the field (onBlur). Then when the user comes back to the field (now dirty), I want the validation to occur onChange. Is it possible to do this ? In RHF, i would do this with the onTouched event - https://www.react-hook-form.com/api/useform/#mode onTouch in RHF - Validation is initially triggered on the first blur event. After that, it is triggered on every change event.
useForm
Performant, flexible and extensible forms with easy-to-use validation.
29 Replies
eastern-cyan
eastern-cyanβ€’13mo ago
@dev Did you ever come up with a solution for this?
extended-salmon
extended-salmonβ€’13mo ago
onChange: ({ value, fieldApi }) => {
if (fieldApi.form.getFieldMeta("yourfieldname")?.isDirty) {
// do the validation
}
}
onChange: ({ value, fieldApi }) => {
if (fieldApi.form.getFieldMeta("yourfieldname")?.isDirty) {
// do the validation
}
}
eastern-cyan
eastern-cyanβ€’13mo ago
Wouldn’t that run as soon the user enters any text? Effectively the same as the default onChange. There’s no isBlurred state.
absent-sapphire
absent-sapphireβ€’13mo ago
We could add a isBlurred state check πŸ™‚ Feel free to make a GH issue or PR for it, it should be really quick
extended-salmon
extended-salmonβ€’13mo ago
I opened a discussion->idea here: https://github.com/TanStack/form/discussions/937
absent-sapphire
absent-sapphireβ€’13mo ago
Let's make a GH issue instead πŸ™‚ Should be easier to track for us, since I know I already wanna add the feature!
extended-salmon
extended-salmonβ€’13mo ago
βœ… Issue is here: https://github.com/TanStack/form/issues/939 I already took a shot at it and opened a PR
absent-sapphire
absent-sapphireβ€’13mo ago
No way!! πŸ˜„ πŸ˜„ πŸ˜„ Thank you! And we're live! Should be deployed in just a mo' here. Thanks for this!
extended-salmon
extended-salmonβ€’13mo ago
That was freaking fast πŸš€ Thanks! Going to put it into my App next πŸ—οΈ
absent-sapphire
absent-sapphireβ€’13mo ago
Uh oh, something borked? (I see you typin' πŸ˜› )
extended-salmon
extended-salmonβ€’13mo ago
I'm afraid there is a bug… 😦 Check the console for "isBlurred" - it's directly true once you start typing into the field. https://stackblitz.com/edit/tanstack-form-xbsuj4?file=src%2Findex.tsx My guess would be that it's this part in the validateField method: https://github.com/TanStack/form/pull/938/files#diff-6f35688436034717856e1ecc1ffda70a9f4eebff9e358bcee1cbbb32ee94b2ceR632-R637 - it's probably called onChange, right?
absent-sapphire
absent-sapphireβ€’13mo ago
Ahh, yup You'll wanna add cause === "blur" (or akin)
extended-salmon
extended-salmonβ€’13mo ago
I'll push a fix
absent-sapphire
absent-sapphireβ€’13mo ago
Thanks! πŸ™‚ Also, if you could, do we wanna write a test to prevent this from regressing in the future?
extended-salmon
extended-salmonβ€’13mo ago
That's what I initially wanted to mention that it feels like there's a test missing for this πŸ™ˆ Turns out that feeling wasn't lying
absent-sapphire
absent-sapphireβ€’13mo ago
Take your time πŸ™‚ It's a new feature, so no fix needed ASAP I'm fighting to get the Angular Redux adapter updated before I need to clock in to my day job otherwise I'd volunteer to fix this That new project's caught my excitement for the moment haha
extended-salmon
extended-salmonβ€’13mo ago
for validateAllFields I'd go for cause === 'submit
absent-sapphire
absent-sapphireβ€’13mo ago
We could also add it to onBlur itself Instead of in validate And in the onSubmit So then we don't need to edgecase the cause (sorry, didn't think of that 'till my brain context switched a bit more)
extended-salmon
extended-salmonβ€’13mo ago
For handleBlur we've got it:
/**
* Handles the blur event.
*/
handleBlur = () => {
const prevTouched = this.state.meta.isTouched
if (!prevTouched) {
this.setMeta((prev) => ({ ...prev, isTouched: true }))
this.validate('change')
}
if (!this.state.meta.isBlurred) {
this.setMeta((prev) => ({ ...prev, isBlurred: true }))
}
this.validate('blur')
}
/**
* Handles the blur event.
*/
handleBlur = () => {
const prevTouched = this.state.meta.isTouched
if (!prevTouched) {
this.setMeta((prev) => ({ ...prev, isTouched: true }))
this.validate('change')
}
if (!this.state.meta.isBlurred) {
this.setMeta((prev) => ({ ...prev, isBlurred: true }))
}
this.validate('blur')
}
the handleSubmit calls validateAllFields('submit') - so that seems fine to keep this code in that function:
if (!field.instance.state.meta.isBlurred && cause === 'submit') {
// Mark them as blurred
field.instance.setMeta((prev) => ({ ...prev, isBlurred: true }))
}
if (!field.instance.state.meta.isBlurred && cause === 'submit') {
// Mark them as blurred
field.instance.setMeta((prev) => ({ ...prev, isBlurred: true }))
}
I'll have to check out for the day soon as well (European here) - I pushed the changes - I'll try to add a test for it tomorrow - https://github.com/TanStack/form/pull/940 pushed two tests as well
stormy-gold
stormy-goldOPβ€’12mo ago
omg i completely forgot i asked this, and i literally came on this discord to ask it again πŸ˜…πŸ˜† thank you for the changes ! is it possible to make a zod validator run only when the meta.isBlurred is true ? i.e
onChange: ({ fieldApi }) => {
fieldApi.state.meta.isBlurred ? z.string().min(3) : undefined;
},
onChange: ({ fieldApi }) => {
fieldApi.state.meta.isBlurred ? z.string().min(3) : undefined;
},
absent-sapphire
absent-sapphireβ€’12mo ago
No, but you can hide your errors until isBlurred is true, which is functionally the same to the user
stormy-gold
stormy-goldOPβ€’12mo ago
It seems like isBlurred is being triggered, even while the user adds input, before I leave the input
<form.Field
name="orgName"
validators={{
onBlur: z.string().min(3),
onChange: z.string().min(3),
}}
children={(field) => {
console.log(field.state.meta);
return (
//Just an input from shadcn/ui
<Input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
<form.Field
name="orgName"
validators={{
onBlur: z.string().min(3),
onChange: z.string().min(3),
}}
children={(field) => {
console.log(field.state.meta);
return (
//Just an input from shadcn/ui
<Input
id={field.name}
name={field.name}
value={field.state.value}
onBlur={field.handleBlur}
onChange={(e) => field.handleChange(e.target.value)}
/>
stormy-gold
stormy-goldOPβ€’12mo ago
and you can see here that isBlurred is true, even though my input hasn't lost focus yet
No description
absent-sapphire
absent-sapphireβ€’12mo ago
Oh, right Memory serving isBlurred shipped in a buggy state I can investigate sometime this week. Please make a GH issue so I don't forget
stormy-gold
stormy-goldOPβ€’12mo ago
also a lil diagram to make sure we're on the same page of what i'm trying to get to
No description
absent-sapphire
absent-sapphireβ€’12mo ago
Sorry, it was a contributor's first PR and they made a followup to fix, but I had IRL stuff come up I understood πŸ™‚ But this is helpful as well if you could include in your issue
stormy-gold
stormy-goldOPβ€’12mo ago
ah lemme go take a look, i was trying to see if something was wrong on my end (not forwardreffing correctly)
extended-salmon
extended-salmonβ€’12mo ago
Here's the fix PR - the initial issue is also referenced there => https://github.com/TanStack/form/pull/940
extended-salmon
extended-salmonβ€’12mo ago
Is there a way I can already use the state as it is in my PR branch in my project (to test it by filling out my form)

Did you find this page helpful?