Skip to content

[BUG] When using zodValidator, even if I set a valid value with setFieldValue, canSubmit does not become true #999

Closed

Description

@koki-iwaizumi

Describe the bug

When using zodValidator, even if I set a valid value with setFieldValue, canSubmit does not become true

import { zodValidator } from '@tanstack/zod-form-adapter'
import { z } from 'zod'

// ...

const formSchema = z.object({
  age:   z.string().optional().refine((data) => data != null && data !== '' && !isNaN(Number(data))),
  ageSub:   z.string().optional().refine((data) => data != null && data !== '' && !isNaN(Number(data))),
})

const form = useForm({
  validatorAdapter: zodValidator(),
  validators: {
    onChange: formSchema
  },
})

const onChangeAge = (handleChange) => (event: React.ChangeEvent<HTMLInputElement>) => {
  handleChange(event.target.value)
  form.setFieldValue('ageSub', event.target.value)  // The validation for ageSub is not being executed here.
}

return (
  <form>
      <form.Field name="age">
        {(field): React.ReactNode => {
          return (
            <Input
              type="number"
              onChange={(e): void => onChangeAge(field.handleChange)}
              value={field.state.value?.toString()}
            />
          )
        }}
    </form.Field>
    <form.Subscribe
      selector={(state): { isDisabled: boolean } => {
        return { isDisabled: state.isPristine || !state.canSubmit }
      }}
    >
      {({ isDisabled }): React.ReactNode => {
        return (
          <Button isDisabled={isDisabled} >
            submit
          </Button>
        )
      }}
    </form.Subscribe>
  </form>
)

In version 0.32.0, canSubmit became true with valid values (e.g., '5' or '6'), but in version 0.33.0, canSubmit remains false.

Expected behavior

I want validation to be executed when setFieldValue is called.

How often does this bug happen?

Every time

Platform

  • OS: Mac
  • Browser: Chrome

TanStack Form adapter

react-form

TanStack Form version

v0.33.0

TypeScript version

v5.6.3

Additional context

If I execute validateField after every setFieldValue call, the validation runs and behaves as expected. However, this was not necessary in version 0.32.0. I would like to know if this behavior is intentional or a bug.

like this.

import { zodValidator } from '@tanstack/zod-form-adapter'
import { z } from 'zod'

// ...

const formSchema = z.object({
  age:   z.string().optional().refine((data) => data != null && data !== '' && !isNaN(Number(data))),
  ageSub:   z.string().optional().refine((data) => data != null && data !== '' && !isNaN(Number(data))),
})

const form = useForm({
  validatorAdapter: zodValidator(),
  validators: {
    onChange: formSchema
  },
})

const onChangeAge = (handleChange) => (event: React.ChangeEvent<HTMLInputElement>) => {
  handleChange(event.target.value)
  form.setFieldValue('ageSub', event.target.value) 

  form.validateField('ageSub', 'change')  // Execute validation here.
}

return (
  <form>
      <form.Field name="age">
        {(field): React.ReactNode => {
          return (
            <Input
              type="number"
              onChange={(e): void => onChangeAge(field.handleChange)}
              value={field.state.value?.toString()}
            />
          )
        }}
    </form.Field>
    <form.Subscribe
      selector={(state): { isDisabled: boolean } => {
        return { isDisabled: state.isPristine || !state.canSubmit }
      }}
    >
      {({ isDisabled }): React.ReactNode => {
        return (
          <Button isDisabled={isDisabled} >
            submit
          </Button>
        )
      }}
    </form.Subscribe>
  </form>
)

I think the behavior change might be due to the changes introduced in #925 , but I'm not certain.

Activity

  1. mfrancis107 commented on Oct 31, 2024

    @mfrancis107

    Adding another example, I think this is probably the same underlying issue.

    https://stackblitz.com/edit/tanstack-form-gpfjb6?file=src%2Findex.tsx

    In this example either (First and Last are required) or Company Name

    Steps to replicate:

    • load page
    • press submit
    • all errors should be shown
    • fill out first and last name
    • We would no expect all errors to disappear
  2. Balastrong commented on Nov 26, 2024

    @Balastrong
    Member

    I think I found the issue, anyone wants to give it a try on a PR?

    The journey starts here:

    if (fieldErrors) {

    If the form validator has field errors they're spread into the fields, but if there are no (more) errors, nothing happens.
    This means that if there are existing errors they're not removed and that's our bug.

    Should be fixed on validateSync and validateAsync.

  3. OrlovAlexei commented on Nov 29, 2024

    @OrlovAlexei

    @mfrancis107 I'm trying to correct in your example. I have a question) should all 3 errors be shown until all fields are filled in?

  4. juanvilladev commented on Feb 17, 2025

    @juanvilladev
    Contributor

    I was able to confirm that this issue is not specific to Zod. canSubmit remains false because the conditions under which we update FieldMeta to sync with the schema are not correct. Will take a crack at this one today.

    See reproduction using native validation:
    https://stackblitz.com/edit/vitejs-vite-pnqeugj1?file=src%2Fcomponents%2FForm.tsx

    • Change interest 2 text to match row 1 ("Interest 1")
    • Notice error message added
    • Change interest 2 to no longer match row 1
    • Notice error does not clear, meaning canSubmit remains false, and FieldMeta not being updated correctly.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions