T
TanStackβ€’17mo ago
fascinating-indigo

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
correct-apricot
correct-apricotβ€’16mo ago
@dev Did you ever come up with a solution for this?
conscious-sapphire
conscious-sapphireβ€’16mo 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
}
}
correct-apricot
correct-apricotβ€’16mo ago
Wouldn’t that run as soon the user enters any text? Effectively the same as the default onChange. There’s no isBlurred state.
correct-apricot
correct-apricotβ€’16mo ago
We could add a isBlurred state check πŸ™‚ Feel free to make a GH issue or PR for it, it should be really quick
conscious-sapphire
conscious-sapphireβ€’15mo ago
I opened a discussion->idea here: https://github.com/TanStack/form/discussions/937
correct-apricot
correct-apricotβ€’15mo ago
Let's make a GH issue instead πŸ™‚ Should be easier to track for us, since I know I already wanna add the feature!
conscious-sapphire
conscious-sapphireβ€’15mo ago
βœ… Issue is here: https://github.com/TanStack/form/issues/939 I already took a shot at it and opened a PR
correct-apricot
correct-apricotβ€’15mo ago
No way!! πŸ˜„ πŸ˜„ πŸ˜„ Thank you! And we're live! Should be deployed in just a mo' here. Thanks for this!
conscious-sapphire
conscious-sapphireβ€’15mo ago
That was freaking fast πŸš€ Thanks! Going to put it into my App next πŸ—οΈ
correct-apricot
correct-apricotβ€’15mo ago
Uh oh, something borked? (I see you typin' πŸ˜› )
conscious-sapphire
conscious-sapphireβ€’15mo 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?
correct-apricot
correct-apricotβ€’15mo ago
Ahh, yup You'll wanna add cause === "blur" (or akin)
conscious-sapphire
conscious-sapphireβ€’15mo ago
I'll push a fix
correct-apricot
correct-apricotβ€’15mo ago
Thanks! πŸ™‚ Also, if you could, do we wanna write a test to prevent this from regressing in the future?
conscious-sapphire
conscious-sapphireβ€’15mo 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
correct-apricot
correct-apricotβ€’15mo 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
conscious-sapphire
conscious-sapphireβ€’15mo ago
for validateAllFields I'd go for cause === 'submit
correct-apricot
correct-apricotβ€’15mo 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)
conscious-sapphire
conscious-sapphireβ€’15mo 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
fascinating-indigo
fascinating-indigoOPβ€’15mo 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;
},
correct-apricot
correct-apricotβ€’15mo ago
No, but you can hide your errors until isBlurred is true, which is functionally the same to the user
fascinating-indigo
fascinating-indigoOPβ€’15mo 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)}
/>
fascinating-indigo
fascinating-indigoOPβ€’15mo ago
and you can see here that isBlurred is true, even though my input hasn't lost focus yet
No description
correct-apricot
correct-apricotβ€’15mo 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
fascinating-indigo
fascinating-indigoOPβ€’15mo ago
also a lil diagram to make sure we're on the same page of what i'm trying to get to
No description
correct-apricot
correct-apricotβ€’15mo 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
fascinating-indigo
fascinating-indigoOPβ€’15mo ago
ah lemme go take a look, i was trying to see if something was wrong on my end (not forwardreffing correctly)
conscious-sapphire
conscious-sapphireβ€’15mo ago
Here's the fix PR - the initial issue is also referenced there => https://github.com/TanStack/form/pull/940
conscious-sapphire
conscious-sapphireβ€’14mo 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?