diff --git a/packages/form-core/src/FieldGroupApi.ts b/packages/form-core/src/FieldGroupApi.ts index e69a29fc9..5e20bb8b2 100644 --- a/packages/form-core/src/FieldGroupApi.ts +++ b/packages/form-core/src/FieldGroupApi.ts @@ -397,6 +397,29 @@ export class FieldGroupApi< return this.form.deleteField(this.getFormFieldName(field)) } + /** + * Delete all fields that belong to this field group. + */ + deleteAllFields = () => { + if (typeof this.fieldsMap === 'string') { + const subFieldsToDelete = Object.keys(this.form.fieldInfo).filter((f) => { + const fieldStr = this.fieldsMap.toString() + return f !== fieldStr && f.startsWith(fieldStr) + }) + + subFieldsToDelete.forEach((field) => { + this.form.deleteField(field) + }) + return + } + + const fieldsMap = this.fieldsMap as FieldsMap + + for (const key in fieldsMap) { + this.deleteField(key) + } + } + /** * Pushes a value into an array field. */ @@ -459,6 +482,20 @@ export class FieldGroupApi< ) } + /** + * Replaces all field values in this field group with the provided values. + */ + replaceAllFields = (fields: TFieldGroupData) => { + for (const fieldName of Object.keys( + fields as object, + ) as (keyof TFieldGroupData)[]) { + this.setFieldValue( + fieldName as unknown as DeepKeys, + fields[fieldName] as never, + ) + } + } + /** * Removes a value from an array field at the specified index. */ @@ -514,12 +551,33 @@ export class FieldGroupApi< } /** - * Resets the field value and meta to default state + * Resets the field value and meta to default state. */ resetField = >(field: TField) => { return this.form.resetField(this.getFormFieldName(field)) } + /** + * Resets all field values and meta within this field group. + */ + resetAllFields = () => { + if (typeof this.fieldsMap === 'string') { + const fieldsToReset = Object.keys(this.form.fieldInfo).filter((f) => { + const fieldStr = this.fieldsMap.toString() + return f !== fieldStr && f.startsWith(fieldStr) + }) + + fieldsToReset.forEach((f) => this.form.resetField(f)) + return + } + + const fieldsMap = this.fieldsMap as FieldsMap + + for (const key in fieldsMap) { + this.resetField(key) + } + } + validateAllFields = (cause: ValidationCause) => this.form.validateAllFields(cause) } diff --git a/packages/form-core/tests/FieldGroupApi.spec.ts b/packages/form-core/tests/FieldGroupApi.spec.ts index 2ff20790d..ccf4ed575 100644 --- a/packages/form-core/tests/FieldGroupApi.spec.ts +++ b/packages/form-core/tests/FieldGroupApi.spec.ts @@ -512,6 +512,127 @@ describe('field group api', () => { expect(form.state.values.nested.field.name).toBeUndefined() }) + it('should deleteAllFields for string field groups', () => { + const defaultValues = { + nested: { + field: { + name: 'hello', + }, + }, + } + + const form = new FormApi({ + defaultValues, + }) + form.mount() + + const field = new FieldApi({ + form, + name: 'nested.field.name', + }) + field.mount() + + const group = new FieldGroupApi({ + defaultValues: { name: '' }, + form, + fields: 'nested.field', + }) + group.mount() + + group.deleteAllFields() + + expect(form.state.values.nested.field).toEqual({}) + }) + + it('should deleteAllFields for mapped field groups', () => { + type FormVals = { + a: string + b: string + } + + const defaultValues: FormVals = { a: 'A', b: 'B' } + const form = new FormApi({ + defaultValues, + }) + form.mount() + + const group = new FieldGroupApi({ + form, + fields: { + firstName: 'a', + lastName: 'b', + }, + defaultValues: { firstName: '', lastName: '' }, + }) + group.mount() + + group.deleteAllFields() + + expect(form.state.values.a).toBeUndefined() + expect(form.state.values.b).toBeUndefined() + }) + + it('should replaceAllFields for string field groups', () => { + const defaultValues: FormValues = { + name: '', + age: 0, + people: [], + relatives: { + father: { + name: 'father', + age: 10, + }, + }, + } + + const form = new FormApi({ + defaultValues, + }) + form.mount() + + const group = new FieldGroupApi({ + defaultValues: {} as Person, + form, + fields: 'relatives.father', + }) + group.mount() + + group.replaceAllFields({ name: 'New name', age: 99 }) + + expect(form.state.values.relatives.father).toEqual({ + name: 'New name', + age: 99, + }) + }) + + it('should replaceAllFields for mapped field groups', () => { + type FormVals = { + a: string + b: string + } + + const defaultValues: FormVals = { a: 'A', b: 'B' } + const form = new FormApi({ + defaultValues, + }) + form.mount() + + const group = new FieldGroupApi({ + form, + fields: { + firstName: 'a', + lastName: 'b', + }, + defaultValues: { firstName: '', lastName: '' }, + }) + group.mount() + + group.replaceAllFields({ firstName: 'X', lastName: 'Y' }) + + expect(form.state.values.a).toBe('X') + expect(form.state.values.b).toBe('Y') + }) + it('should forward array methods to the form', async () => { vi.useFakeTimers() const defaultValues = {