diff --git a/docs/reference/react/useForm.md b/docs/reference/react/useForm.md index c3a30c2..75323e8 100644 --- a/docs/reference/react/useForm.md +++ b/docs/reference/react/useForm.md @@ -12,7 +12,7 @@ declare function useForm< TData, TAdapter extends ValidatorAdapter | undefined = undefined, >( - options: FormLogicOptions, + options?: FormLogicOptions, ): FormContextType; ``` diff --git a/packages/form-core/src/FormLogic.spec.ts b/packages/form-core/src/FormLogic.spec.ts index ee0994c..8a4aba4 100644 --- a/packages/form-core/src/FormLogic.spec.ts +++ b/packages/form-core/src/FormLogic.spec.ts @@ -42,9 +42,12 @@ const adapter: ValidatorAdapter = { describe('FormLogic', () => { it('should have the correct initial state', () => { const form = new FormLogic() + + expect(form.isMounted.value).toBeFalsy() form.mount() + expect(form.isMounted.value).toBeTruthy() - expect(form.fields.peek().length).toBe(0) + expect(form.fields.value.length).toBe(0) expect(form.data.value).toStrictEqual({}) expect(form.json.value).toStrictEqual({}) @@ -470,6 +473,42 @@ describe('FormLogic', () => { form.updateOptions({ defaultValues: { name: 'another' } }) expect(form.data.value.name.value).toBe('another') }) + it('should be able to remove fields of dynamic objects or items from an array when updating the options', () => { + const form = new FormLogic<{ + obj: { [key: string]: string } + array: number[] + }>({ + defaultValues: { + obj: { + stay: 'stay', + go: 'go', + }, + array: [1, 2, 3], + }, + }) + form.mount() + + expect(form.json.value).toEqual({ + obj: { + stay: 'stay', + go: 'go', + }, + array: [1, 2, 3], + }) + form.updateOptions({ + defaultValues: { + obj: { stay: 'stay(changed)', new: 'new' }, + array: [2], + }, + }) + expect(form.json.value).toEqual({ + obj: { + stay: 'stay(changed)', + new: 'new', + }, + array: [2], + }) + }) it('should update the data when using the handleChange method', () => { const form = new FormLogic<{ name: string }>() @@ -1804,6 +1843,22 @@ describe('FormLogic', () => { expect(form.data.value.deep.value.new.value).toBe(2) expect(fn).toHaveBeenCalledTimes(1) }) + it('should touch a field when adding a new key to an object if configured', () => { + const form = new FormLogic<{ deep: { [key: string]: number } }>({ + defaultValues: { + deep: { + value: 1, + }, + }, + }) + form.mount() + const field = new FieldLogic(form, 'deep') + field.mount() + + expect(field.isTouched.value).toBe(false) + form.setValueInObject('deep', 'new', 2, { shouldTouch: true }) + expect(field.isTouched.value).toBe(true) + }) it('should update a value in an object that already has the key', () => { const form = new FormLogic<{ deep: { [key: string]: number } }>({ defaultValues: { @@ -1881,6 +1936,22 @@ describe('FormLogic', () => { expect(form.data.value.deep.value.value).toBeUndefined() expect(fn).toHaveBeenCalledTimes(1) }) + it('should touch a field when removing a key from an object if configured', () => { + const form = new FormLogic<{ deep: { value?: number } }>({ + defaultValues: { + deep: { + value: 1, + }, + }, + }) + form.mount() + const field = new FieldLogic(form, 'deep') + field.mount() + + expect(field.isTouched.value).toBe(false) + form.removeValueInObject('deep', 'value', { shouldTouch: true }) + expect(field.isTouched.value).toBe(true) + }) it('should do nothing when trying to remove a key to a value that is not an object or a date', () => { const form = new FormLogic({ defaultValues: { diff --git a/packages/form-core/src/FormLogic.ts b/packages/form-core/src/FormLogic.ts index 1de9e22..483c3c3 100644 --- a/packages/form-core/src/FormLogic.ts +++ b/packages/form-core/src/FormLogic.ts @@ -27,7 +27,6 @@ import { isEqualDeep, makeArrayEntry, removeSignalValueAtPath, - removeValueAtPath, setSignalValueAtPath, setSignalValuesFromObject, setValueAtPath, @@ -394,9 +393,9 @@ export class FormLogic< // We do not want to update dirty field values, since we do not want to reset the form, but just override the default values const newDefaultValues = { ...options.defaultValues } for (const dirtyField of dirtyFields) { - removeValueAtPath(newDefaultValues, dirtyField as never) + setValueAtPath(newDefaultValues, dirtyField as never, undefined) } - setSignalValuesFromObject(this._data, newDefaultValues, true) + setSignalValuesFromObject(this._data, newDefaultValues) } /** diff --git a/packages/form-react/src/form/form.hooks.tsx b/packages/form-react/src/form/form.hooks.tsx index 0539941..646772c 100644 --- a/packages/form-react/src/form/form.hooks.tsx +++ b/packages/form-react/src/form/form.hooks.tsx @@ -22,7 +22,7 @@ export function useForm< TData, TAdapter extends ValidatorAdapter | undefined = undefined, >( - options: FormLogicOptions, + options?: FormLogicOptions, ): FormContextType { // biome-ignore lint/correctness/useExhaustiveDependencies: We only ever want to create a form once const finalForm = React.useMemo(() => {