Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/calm-fields-reset.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/form-core': patch
---

Fix `form.resetField()` leaving the current value in place when the field's default value is `undefined`. The field is now reset to `undefined`, matching `form.reset()` and `isDefaultValue`.
9 changes: 5 additions & 4 deletions packages/form-core/src/FormApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2941,17 +2941,18 @@ export class FormApi<
this.getFieldInfo(field).instance?.options.defaultValue
const formDefault = getBy(this.options.defaultValues, field)
const targetValue = fieldDefault ?? formDefault
const hasDefault =
fieldDefault !== undefined || this.options.defaultValues !== undefined
Comment thread
coderabbitai[bot] marked this conversation as resolved.

return {
...prev,
fieldMetaBase: {
...prev.fieldMetaBase,
[field]: defaultFieldMeta,
},
values:
targetValue !== undefined
? setBy(prev.values, field, targetValue)
: prev.values,
values: hasDefault
? setBy(prev.values, field, targetValue)
: prev.values,
}
})
}
Expand Down
96 changes: 96 additions & 0 deletions packages/form-core/tests/FormApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4236,6 +4236,102 @@ it('should preserve nested fields on resetField if defaultValues is not provided
expect(form.state.values.nested.field.name).toEqual('Nested')
})

it.each([
['undefined', undefined],
['null', null],
['an empty string', ''],
['false', false],
['0', 0],
['a defined value', 'tony'],
])(
'should reset a field to a form-level default of %s on resetField',
(_, defaultValue) => {
const form = new FormApi({
defaultValues: { name: defaultValue } as { name: unknown },
})
form.mount()

const field = new FieldApi({ form, name: 'name' })
field.mount()

field.setValue('hawk')
expect(field.getMeta().isDefaultValue).toBe(false)

form.resetField('name')

expect(form.state.values.name).toBe(defaultValue)
expect(field.state.value).toBe(defaultValue)
expect(field.getMeta().isDefaultValue).toBe(true)
expect(field.getMeta().isTouched).toBe(false)
},
)

it('should reset a field to undefined on resetField if its key is missing from defaultValues', () => {
const form = new FormApi({
defaultValues: {} as { name?: string },
})
form.mount()

const field = new FieldApi({ form, name: 'name' })
field.mount()

field.setValue('hawk')
form.resetField('name')

expect(form.state.values.name).toBeUndefined()
expect(field.getMeta().isDefaultValue).toBe(true)
})

it('should reset nested fields with undefined defaults on resetField without changing their siblings', () => {
const form = new FormApi({
defaultValues: {
nested: { name: undefined, age: 1 },
people: [{ name: undefined }, { name: 'second' }],
} as {
nested: { name?: string; age: number }
people: { name?: string }[]
},
})
form.mount()

form.setFieldValue('nested.name', 'Nested')
form.setFieldValue('nested.age', 2)
form.setFieldValue('people[0].name', 'first')
form.setFieldValue('people[1].name', 'changed')

form.resetField('nested.name')
form.resetField('people[0].name')

expect(form.state.values).toEqual({
nested: { name: undefined, age: 2 },
people: [{ name: undefined }, { name: 'changed' }],
})
})

it.each([
['a defined value', 'tony'],
['an empty string', ''],
['false', false],
['0', 0],
])(
'should reset a field to a field-level default of %s on resetField if defaultValues is not provided',
(_, defaultValue) => {
const form = new FormApi({
defaultState: { values: { name: 'initial' } as { name: unknown } },
})
form.mount()

const field = new FieldApi({ form, name: 'name', defaultValue })
field.mount()

field.setValue('hawk')
form.resetField('name')

expect(form.state.values.name).toBe(defaultValue)
expect(field.getMeta().isDefaultValue).toBe(true)
},
)

it('should accept formId and return it', () => {
const form = new FormApi({
defaultValues: { age: 0 },
Expand Down