diff --git a/packages/form-core/src/utils.ts b/packages/form-core/src/utils.ts index 46849d518..6aec9cb06 100644 --- a/packages/form-core/src/utils.ts +++ b/packages/form-core/src/utils.ts @@ -49,7 +49,10 @@ export function setBy(obj: any, _path: any, updater: Updater) { const key = path.shift() - if (typeof key === 'string') { + if ( + typeof key === 'string' || + (typeof key === 'number' && !Array.isArray(parent)) + ) { if (typeof parent === 'object') { if (parent === null) { parent = {} @@ -64,7 +67,7 @@ export function setBy(obj: any, _path: any, updater: Updater) { } } - if (Array.isArray(parent) && key !== undefined) { + if (Array.isArray(parent) && typeof key === 'number') { const prefix = parent.slice(0, key) return [ ...(prefix.length ? prefix : new Array(key)), diff --git a/packages/form-core/tests/FieldApi.spec.ts b/packages/form-core/tests/FieldApi.spec.ts index 50756687b..4a6dbf2de 100644 --- a/packages/form-core/tests/FieldApi.spec.ts +++ b/packages/form-core/tests/FieldApi.spec.ts @@ -485,6 +485,29 @@ describe('field api', () => { ]) }) + it('should add a field when the key is numeric but the parent is not an array', () => { + const form = new FormApi({ + defaultValues: { + items: {} as Record, + }, + }) + + const field = new FieldApi({ + form, + name: 'items.2.quantity', + }) + + field.setValue(10) + + expect(form.state.values).toStrictEqual({ + items: { + 2: { + quantity: 10, + }, + }, + }) + }) + it('should not throw errors when no meta info is stored on a field and a form re-renders', async () => { const form = new FormApi({ defaultValues: { diff --git a/packages/form-core/tests/utils.spec.ts b/packages/form-core/tests/utils.spec.ts index 7e6a8c12c..d5b55f566 100644 --- a/packages/form-core/tests/utils.spec.ts +++ b/packages/form-core/tests/utils.spec.ts @@ -65,6 +65,29 @@ describe('setBy', () => { setBy(structure, 'kids[0].hobbies[1]', 'gaming').kids[0].hobbies[1], ).toBe('gaming') }) + + it("should create an object if it doesn't exist", () => { + expect(setBy(structure, 'father.name', 'John').father.name).toBe('John') + }) + + it('should create an array if it doesnt exist', () => { + expect(setBy(structure, 'kids[2].name', 'John').kids[2].name).toBe('John') + }) + + it('should set a value in an object if the key is a number but the parent is an object', () => { + const newStructure = setBy(structure, '5.name', 'John') + expect(newStructure['5'].name).toBe('John') + expect(newStructure).toStrictEqual({ ...structure, 5: { name: 'John' } }) + }) + + it('should set a value in an array if the key is a number and the parent is an array', () => { + const newStructure = setBy(structure, 'kids.2.name', 'John') + expect(newStructure.kids[2].name).toBe('John') + expect(newStructure).toStrictEqual({ + ...structure, + kids: [...structure.kids, { name: 'John' }], + }) + }) }) describe('deleteBy', () => {