Skip to content

Commit

Permalink
fix(form-core): handle numeric keys as array index only if parent is …
Browse files Browse the repository at this point in the history
…an array (#993)
  • Loading branch information
Balastrong authored Nov 25, 2024
1 parent 46d9269 commit a4e76c8
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 2 deletions.
7 changes: 5 additions & 2 deletions packages/form-core/src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,10 @@ export function setBy(obj: any, _path: any, updater: Updater<any>) {

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 = {}
Expand All @@ -64,7 +67,7 @@ export function setBy(obj: any, _path: any, updater: Updater<any>) {
}
}

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)),
Expand Down
23 changes: 23 additions & 0 deletions packages/form-core/tests/FieldApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<number, { quantity: number }>,
},
})

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: {
Expand Down
23 changes: 23 additions & 0 deletions packages/form-core/tests/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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', () => {
Expand Down

0 comments on commit a4e76c8

Please sign in to comment.