From d0d2271d3f6e8b8403ead59a09602bd9464fa5ba Mon Sep 17 00:00:00 2001 From: Kamil Kusy Date: Tue, 14 Oct 2025 20:01:58 +0200 Subject: [PATCH] fix(form-core): fix deleteField method --- packages/form-core/src/FieldApi.ts | 5 +++- packages/form-core/src/FormApi.ts | 40 ++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 1 deletion(-) diff --git a/packages/form-core/src/FieldApi.ts b/packages/form-core/src/FieldApi.ts index 7317d70a1..fb80a7bf6 100644 --- a/packages/form-core/src/FieldApi.ts +++ b/packages/form-core/src/FieldApi.ts @@ -1232,7 +1232,10 @@ export class FieldApi< mount = () => { const cleanup = this.store.mount() - if ((this.options.defaultValue as unknown) !== undefined) { + if ( + (this.options.defaultValue as unknown) !== undefined && + !this.form.isFieldDeleted(this.name) + ) { this.form.setFieldValue(this.name, this.options.defaultValue as never, { dontUpdateMeta: true, }) diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index 611941b19..8f23cd9ec 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -975,6 +975,12 @@ export class FormApi< * @private */ private _devtoolsSubmissionOverride: boolean + /** + * @private + * Tracks fields that have been explicitly deleted via deleteField() + * to prevent them from being restored by field mount() with defaultValue + */ + private _deletedFields: Set = new Set() /** * Constructs a new `FormApi` instance with the given form options. @@ -1468,6 +1474,8 @@ export class FormApi< const { fieldMeta: currentFieldMeta } = this.state const fieldMetaBase = this.resetFieldMeta(currentFieldMeta) + this._deletedFields.clear() + if (values && !opts?.keepDefaultValues) { this.options = { ...this.options, @@ -1642,6 +1650,11 @@ export class FormApi< for (const field of Object.keys( this.state.fieldMeta, ) as DeepKeys[]) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (this.baseStore.state.fieldMetaBase[field] === undefined) { + continue + } + const fieldMeta = this.getFieldMeta(field) if (!fieldMeta) continue @@ -1845,6 +1858,11 @@ export class FormApi< for (const field of Object.keys( this.state.fieldMeta, ) as DeepKeys[]) { + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + if (this.baseStore.state.fieldMetaBase[field] === undefined) { + continue + } + const fieldMeta = this.getFieldMeta(field) if (!fieldMeta) continue @@ -2219,6 +2237,14 @@ export class FormApi< const dontRunListeners = opts?.dontRunListeners ?? false const dontValidate = opts?.dontValidate ?? false + if (this._deletedFields.has(field as string)) { + return + } + + if (!opts?.dontUpdateMeta) { + this._deletedFields.delete(field as string) + } + batch(() => { if (!dontUpdateMeta) { this.setFieldMeta(field, (prev) => ({ @@ -2250,6 +2276,14 @@ export class FormApi< } } + /** + * Checks if a field has been explicitly deleted and should not be restored + * @private + */ + isFieldDeleted = >(field: TField) => { + return this._deletedFields.has(field as string) + } + deleteField = >(field: TField) => { const subFieldsToDelete = Object.keys(this.fieldInfo).filter((f) => { const fieldStr = field.toString() @@ -2258,6 +2292,10 @@ export class FormApi< const fieldsToDelete = [...subFieldsToDelete, field] + fieldsToDelete.forEach((f) => { + this._deletedFields.add(f) + }) + // Cleanup the last fields this.baseStore.setState((prev) => { const newState = { ...prev } @@ -2472,6 +2510,8 @@ export class FormApi< * Resets the field value and meta to default state */ resetField = >(field: TField) => { + this._deletedFields.delete(field as string) + this.baseStore.setState((prev) => { return { ...prev,