diff --git a/docs/reference/fieldApi.md b/docs/reference/fieldApi.md index dbfd4031..993315d0 100644 --- a/docs/reference/fieldApi.md +++ b/docs/reference/fieldApi.md @@ -265,7 +265,12 @@ A class representing the API for managing a form field. insertValue(index: number, value: TData): void ``` - - Inserts a value at the specified index. + - Inserts a value at the specified index, shifting the subsequent values to the right. + +- ```tsx + replaceValue(index: number, value: TData): void + ``` + - Replaces a value at the specified index. - ```tsx removeValue(index: number): Promise diff --git a/docs/reference/formApi.md b/docs/reference/formApi.md index 04f293db..c61d3968 100644 --- a/docs/reference/formApi.md +++ b/docs/reference/formApi.md @@ -177,7 +177,11 @@ A class representing the Form API. It handles the logic and interactions with th - ```tsx insertFieldValue>(field: TField, index: number, value: DeepValue, opts?: { touch?: boolean }) ``` - - Inserts a value into an array field at the specified index. + - Inserts a value into an array field at the specified index, shifting the subsequent values to the right. +- ```tsx + replaceFieldValue>(field: TField, index: number, value: DeepValue, opts?: { touch?: boolean }) + ``` + - Replaces a value into an array field at the specified index. - ```tsx removeFieldValue>(field: TField, index: number, opts?: { touch?: boolean }) ``` diff --git a/packages/form-core/src/FieldApi.ts b/packages/form-core/src/FieldApi.ts index 46d69874..6790b4f9 100644 --- a/packages/form-core/src/FieldApi.ts +++ b/packages/form-core/src/FieldApi.ts @@ -477,6 +477,11 @@ export class FieldApi< value: TData extends any[] ? TData[number] : never, ) => this.form.insertFieldValue(this.name, index, value as any) + replaceValue = ( + index: number, + value: TData extends any[] ? TData[number] : never, + ) => this.form.replaceFieldValue(this.name, index, value as any) + removeValue = (index: number, opts?: { touch: boolean }) => this.form.removeFieldValue(this.name, index, opts) diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index 87016428..3d1201d3 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -757,6 +757,30 @@ export class FormApi< ? DeepValue[number] : never, opts?: { touch?: boolean }, + ) => { + this.setFieldValue( + field, + (prev) => { + return [ + ...(prev as DeepValue[]).slice(0, index), + value, + ...(prev as DeepValue[]).slice(index), + ] as any + }, + opts, + ) + + // Validate the whole array + all fields that have shifted + await this.validateField(field, 'change') + } + + replaceFieldValue = async >( + field: TField, + index: number, + value: DeepValue extends any[] + ? DeepValue[number] + : never, + opts?: { touch?: boolean }, ) => { this.setFieldValue( field, diff --git a/packages/form-core/src/tests/FieldApi.spec.ts b/packages/form-core/src/tests/FieldApi.spec.ts index a35109f8..5e842cc8 100644 --- a/packages/form-core/src/tests/FieldApi.spec.ts +++ b/packages/form-core/src/tests/FieldApi.spec.ts @@ -150,7 +150,41 @@ describe('field api', () => { field.insertValue(1, 'other') - expect(field.getValue()).toStrictEqual(['one', 'other']) + expect(field.getValue()).toStrictEqual(['one', 'other', 'two']) + }) + + it('should replace a value into an array correctly', () => { + const form = new FormApi({ + defaultValues: { + names: ['one', 'two', 'three'], + }, + }) + + const field = new FieldApi({ + form, + name: 'names', + }) + + field.replaceValue(1, 'other') + + expect(field.getValue()).toStrictEqual(['one', 'other', 'three']) + }) + + it('should do nothing when replacing a value into an array at an index that does not exist', () => { + const form = new FormApi({ + defaultValues: { + names: ['one', 'two', 'three'], + }, + }) + + const field = new FieldApi({ + form, + name: 'names', + }) + + field.replaceValue(10, 'other') + + expect(field.getValue()).toStrictEqual(['one', 'two', 'three']) }) it('should run onChange validation when inserting an array fields value', () => { diff --git a/packages/form-core/src/tests/FormApi.spec.ts b/packages/form-core/src/tests/FormApi.spec.ts index 1390002b..559298a6 100644 --- a/packages/form-core/src/tests/FormApi.spec.ts +++ b/packages/form-core/src/tests/FormApi.spec.ts @@ -324,6 +324,23 @@ describe('form api', () => { expect(form.getFieldValue('names')).toStrictEqual(['test', 'other']) }) + it("should insert an array field's value as first element", () => { + const form = new FormApi({ + defaultValues: { + names: ['one', 'two', 'three'], + }, + }) + form.mount() + form.insertFieldValue('names', 0, 'other') + + expect(form.getFieldValue('names')).toStrictEqual([ + 'other', + 'one', + 'two', + 'three', + ]) + }) + it("should run onChange validation when pushing an array field's value", () => { const form = new FormApi({ defaultValues: { @@ -352,9 +369,55 @@ describe('form api', () => { form.mount() form.insertFieldValue('names', 1, 'other') + expect(form.getFieldValue('names')).toStrictEqual([ + 'one', + 'other', + 'two', + 'three', + ]) + }) + + it("should insert an array field's value at the end if the index is higher than the length", () => { + const form = new FormApi({ + defaultValues: { + names: ['one', 'two', 'three'], + }, + }) + form.mount() + form.insertFieldValue('names', 10, 'other') + + expect(form.getFieldValue('names')).toStrictEqual([ + 'one', + 'two', + 'three', + 'other', + ]) + }) + + it("should replace an array field's value", () => { + const form = new FormApi({ + defaultValues: { + names: ['one', 'two', 'three'], + }, + }) + form.mount() + form.replaceFieldValue('names', 1, 'other') + expect(form.getFieldValue('names')).toStrictEqual(['one', 'other', 'three']) }) + it("should do nothing when replacing an array field's value with an index that doesn't exist", () => { + const form = new FormApi({ + defaultValues: { + names: ['one', 'two', 'three'], + }, + }) + form.mount() + form.replaceFieldValue('names', 10, 'other') + + expect(form.getFieldValue('names')).toStrictEqual(['one', 'two', 'three']) + }) + it("should run onChange validation when inserting an array field's value", () => { const form = new FormApi({ defaultValues: { @@ -400,7 +463,7 @@ describe('form api', () => { expect(field1.state.meta.errors).toStrictEqual([]) - await form.insertFieldValue('names', 0, { first: 'other' }) + await form.replaceFieldValue('names', 0, { first: 'other' }) expect(field1.state.meta.errors).toStrictEqual(['Invalid value']) })