TanStack / form

🤖 Powerful and type-safe form state management for the web. TS/JS, React Form, Solid Form, Lit Form and Vue Form.
https://tanstack.com/form
MIT License
3.61k stars 325 forks source link

Mismatch in array handling between useForm and FormData #665

Closed probablykabari closed 5 months ago

probablykabari commented 5 months ago

Describe the bug

In the docs, everywhere that array fields are mentioned the format is different than what works on the server. Take this example:

<form.Field key={i} name={`people[${i}].name`}>
  {(subField) => (
    <input
      value={subField.state.value}
      onChange={(e) =>
        subField.handleChange(e.target.value)
      }
    />
  )}
</form.Field>

In FormData this will become { "people[0].name": "value" } and will not validate because the decode-formdata library expects the format to be { "people.0.name": "value } or { "people.[0].name": "value } and thus the value is empty.

See line https://github.com/TanStack/form/blob/9ecc5e26b9a43ef4117a1db311671719a741e41f/packages/react-form/src/validateFormData.ts#L60

Note: Currently a workaround is simply to not use <input name={subField.name} ... /> on the input and instead do <input name={'people.${i}.name'} ... /> . So this may be resolved by highlighting this in the React docs.

Your minimal, reproducible example

Not sure how to run tests on those TBH

Steps to reproduce

Example test suite provided

Expected behavior

type FormSchema = {
  people: { name: string }[]
}
const factory = createFormFactory<FormSchema>({
  defaultValues: {
    people: []
  },
  onServerValidate({ value }) {
    if (!value.people) return `People is required but is ${typeof value.people}`
    if (value.people.length < 1) return "Not enough people to party"
  }
})

async function action(prev: unknown, data: FormData) {
  return await factory.validateFormData(data)
}

test("array validation for people[0].name", async ({ expect }) => {
  const formData = new FormData()

  formData.set("people[0].name", "Joe")
  formData.set("people[1].name", "Jane")

  expect(await action(null, formData)).toEqual({
    errorMap: {
      onServer: undefined
    },
    errors: []
  })
})
test("array validation for people.0.name", async ({ expect }) => {
  const formData = new FormData()

  formData.set("people.0.name", "Joe")
  formData.set("people.1.name", "Jane")

  expect(await action(null, formData)).toEqual({
    errorMap: {
      onServer: undefined
    },
    errors: []
  })
})

test("array validation for people.[0].name", async ({ expect }) => {
  const formData = new FormData()

  formData.set("people.[0].name", "Joe")
  formData.set("people.[1].name", "Jane")

  expect(await action(null, formData)).toEqual({
    errorMap: {
      onServer: undefined
    },
    errors: []
  })
})

Result:

test:    × array validation for people[0].name
test:    ✓ array validation for people.0.name
test:    ✓ array validation for people.[0].name

test:  FAIL  __tests__/array.ts > array validation for people[0].name
test: AssertionError: expected { …(2) } to deeply equal { …(2) }
test: 
test: - Expected
test: + Received
test: 
test:   Object {
test:     "errorMap": Object {
test: -     "onServer": undefined,
test: +     "onServer": "People is required but is undefined",
test:     },
test: -   "errors": Array [],
test: +   "errors": Array [
test: +     "People is required but is undefined",
test: +   ],
test:   }

How often does this bug happen?

Every time

Screenshots or Videos

No response

Platform

Vitest

TanStack Form adapter

react-form

TanStack Form version

0.19.0

TypeScript version

5.3.2

Additional context

No response

crutchcorn commented 5 months ago

This is where our docs could be improved. Unfortunately, due to the complexity of FormData parsing, we're handing off that "everything is a string" parsing to decode-formdata: https://github.com/fabian-hiller/decode-formdata

Where you need to pass in the schema you expect the FormData to parse to on the server. Closing as a can't fix, but do feel free to make a PR to docs to clarify this for us if you're comfortable doing so :)

probablykabari commented 4 months ago

@crutchcorn Mind if I make a bigger PR to address the following, all related to using server validation. Thus far my usage in practice has been less than welcoming.

crutchcorn commented 4 months ago

@probablykabari thanks for reporting these. Glad to see someones validating our SSR stuff in prod.

Both of these sound like bugs, not docs issues. The first should be easy to solve and the second might be a slight addon to mergeForm or something.

PRs are always welcome 😊