@tanstack/form-core
Advanced tools
Comparing version
@@ -87,3 +87,5 @@ import { Store } from '@tanstack/store'; | ||
insertValue: (index: number, value: TData extends any[] ? TData[number] : never) => void; | ||
removeValue: (index: number) => void; | ||
removeValue: (index: number, opts?: { | ||
touch: boolean; | ||
}) => Promise<void>; | ||
swapValues: (aIndex: number, bIndex: number) => void; | ||
@@ -90,0 +92,0 @@ getLinkedFields: (cause: ValidationCause) => FieldApi<any, any, any, any, any>[]; |
@@ -84,3 +84,5 @@ import { Store } from "@tanstack/store"; | ||
this.insertValue = (index, value) => this.form.insertFieldValue(this.name, index, value); | ||
this.removeValue = (index) => this.form.removeFieldValue(this.name, index); | ||
this.removeValue = async (index, opts2) => { | ||
await this.form.removeFieldValue(this.name, index, opts2); | ||
}; | ||
this.swapValues = (aIndex, bIndex) => this.form.swapFieldValues(this.name, aIndex, bIndex); | ||
@@ -87,0 +89,0 @@ this.getLinkedFields = (cause) => { |
@@ -119,5 +119,5 @@ import { Store } from '@tanstack/store'; | ||
touch?: boolean; | ||
}) => void; | ||
}) => Promise<void>; | ||
swapFieldValues: <TField extends DeepKeys<TFormData>>(field: TField, index1: number, index2: number) => void; | ||
moveFieldValues: <TField extends DeepKeys<TFormData>>(field: TField, index1: number, index2: number) => void; | ||
} |
@@ -362,3 +362,5 @@ import { Store } from "@tanstack/store"; | ||
}; | ||
this.removeFieldValue = (field, index, opts2) => { | ||
this.removeFieldValue = async (field, index, opts2) => { | ||
const fieldValue = this.getFieldValue(field); | ||
const lastIndex = Array.isArray(fieldValue) ? Math.max(fieldValue.length - 1, 0) : null; | ||
this.setFieldValue( | ||
@@ -373,2 +375,10 @@ field, | ||
); | ||
if (lastIndex !== null) { | ||
const start = `${field}[${lastIndex}]`; | ||
const fieldsToDelete = Object.keys(this.fieldInfo).filter( | ||
(f) => f.startsWith(start) | ||
); | ||
fieldsToDelete.forEach((f) => this.deleteField(f)); | ||
} | ||
await this.validateAllFields("change"); | ||
}; | ||
@@ -375,0 +385,0 @@ this.swapFieldValues = (field, index1, index2) => { |
{ | ||
"name": "@tanstack/form-core", | ||
"version": "0.20.0", | ||
"version": "0.20.1", | ||
"description": "Powerful, type-safe, framework agnostic forms.", | ||
@@ -5,0 +5,0 @@ "author": "tannerlinsley", |
@@ -480,3 +480,5 @@ import { Store } from '@tanstack/store' | ||
removeValue = (index: number) => this.form.removeFieldValue(this.name, index) | ||
removeValue = async (index: number, opts?: { touch: boolean }) => { | ||
await this.form.removeFieldValue(this.name, index, opts) | ||
} | ||
@@ -483,0 +485,0 @@ swapValues = (aIndex: number, bIndex: number) => |
@@ -718,3 +718,3 @@ import { Store } from '@tanstack/store' | ||
removeFieldValue = <TField extends DeepKeys<TFormData>>( | ||
removeFieldValue = async <TField extends DeepKeys<TFormData>>( | ||
field: TField, | ||
@@ -724,2 +724,8 @@ index: number, | ||
) => { | ||
const fieldValue = this.getFieldValue(field) | ||
const lastIndex = Array.isArray(fieldValue) | ||
? Math.max(fieldValue.length - 1, 0) | ||
: null | ||
this.setFieldValue( | ||
@@ -734,2 +740,14 @@ field, | ||
) | ||
if (lastIndex !== null) { | ||
const start = `${field}[${lastIndex}]` | ||
const fieldsToDelete = Object.keys(this.fieldInfo).filter((f) => | ||
f.startsWith(start), | ||
) | ||
// Cleanup the last fields | ||
fieldsToDelete.forEach((f) => this.deleteField(f as TField)) | ||
} | ||
await this.validateAllFields('change') | ||
} | ||
@@ -736,0 +754,0 @@ |
@@ -144,2 +144,113 @@ import { describe, expect, it, vi } from 'vitest' | ||
it('should remove a subfield from an array field correctly', async () => { | ||
const form = new FormApi({ | ||
defaultValues: { | ||
people: [] as Array<{ name: string }>, | ||
}, | ||
}) | ||
const field = new FieldApi({ | ||
form, | ||
name: 'people', | ||
}) | ||
const subFieldValidators = { | ||
onChange: ({ value }: { value: string }) => | ||
value.length === 0 ? 'Required' : null, | ||
} | ||
const subField1 = new FieldApi({ | ||
form: field.form, | ||
name: 'people[0].name', | ||
defaultValue: '', | ||
validators: subFieldValidators, | ||
}) | ||
const subField2 = new FieldApi({ | ||
form: field.form, | ||
name: 'people[1].name', | ||
defaultValue: 'hello', | ||
validators: subFieldValidators, | ||
}) | ||
const subField3 = new FieldApi({ | ||
form: field.form, | ||
name: 'people[2].name', | ||
defaultValue: '', | ||
validators: subFieldValidators, | ||
}) | ||
const subField4 = new FieldApi({ | ||
form: field.form, | ||
name: 'people[3].name', | ||
defaultValue: 'world', | ||
validators: subFieldValidators, | ||
}) | ||
;[form, field, subField1, subField2, subField3, subField4].forEach((f) => | ||
f.mount(), | ||
) | ||
await form.handleSubmit() | ||
expect(subField1.state.meta.errorMap.onChange).toStrictEqual('Required') | ||
expect(subField2.state.meta.errorMap.onChange).toStrictEqual(undefined) | ||
expect(subField3.state.meta.errorMap.onChange).toStrictEqual('Required') | ||
expect(subField4.state.meta.errorMap.onChange).toStrictEqual(undefined) | ||
await field.removeValue(0 /* subField1 */, { touch: true }) | ||
expect(subField1.state.value).toBe('hello') | ||
expect(subField1.state.meta.errorMap.onChange).toStrictEqual(undefined) | ||
expect(subField2.state.value).toBe('') | ||
expect(subField2.state.meta.errorMap.onChange).toStrictEqual('Required') | ||
expect(subField3.state.value).toBe('world') | ||
expect(subField3.state.meta.errorMap.onChange).toStrictEqual(undefined) | ||
expect(form.getFieldInfo('people[0].name').instance?.state.value).toBe( | ||
'hello', | ||
) | ||
expect(form.getFieldInfo('people[1].name').instance?.state.value).toBe('') | ||
expect(form.getFieldInfo('people[2].name').instance?.state.value).toBe( | ||
'world', | ||
) | ||
}) | ||
it('should remove remove the last subfield from an array field correctly', async () => { | ||
const form = new FormApi({ | ||
defaultValues: { | ||
people: [] as Array<{ name: string }>, | ||
}, | ||
}) | ||
const field = new FieldApi({ | ||
form, | ||
name: 'people', | ||
}) | ||
const subFieldValidators = { | ||
onChange: ({ value }: { value: string }) => | ||
value.length === 0 ? 'Required' : null, | ||
} | ||
const subField1 = new FieldApi({ | ||
form: field.form, | ||
name: 'people[0].name', | ||
defaultValue: '', | ||
validators: subFieldValidators, | ||
}) | ||
;[form, field, subField1].forEach((f) => f.mount()) | ||
await form.handleSubmit() | ||
expect(subField1.state.meta.errorMap.onChange).toStrictEqual('Required') | ||
await field.removeValue(0 /* subField1 */, { touch: true }) | ||
expect(subField1.state.value).toBe(undefined) | ||
expect(subField1.state.meta.errorMap.onChange).toStrictEqual(undefined) | ||
expect(form.state.canSubmit).toBe(true) | ||
}) | ||
it('should swap a value from an array value correctly', () => { | ||
@@ -146,0 +257,0 @@ const form = new FormApi({ |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
388309
1.77%6535
2.03%