diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index d710cd105..cc5bed9be 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -2659,13 +2659,12 @@ export class FormApi< batch(() => { if (!dontUpdateMeta) { - this.setFieldMeta(field, (prev) => ({ + this.setFieldMeta(field, (prev = defaultFieldMeta) => ({ ...prev, isTouched: true, isDirty: true, errorMap: { - // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition - ...prev?.errorMap, + ...prev.errorMap, onMount: undefined, }, })) diff --git a/packages/form-core/tests/FormApi.spec.ts b/packages/form-core/tests/FormApi.spec.ts index 024b319f0..802801e7f 100644 --- a/packages/form-core/tests/FormApi.spec.ts +++ b/packages/form-core/tests/FormApi.spec.ts @@ -83,6 +83,36 @@ describe('form api', () => { }) }) + it('should create complete meta when setFieldValue targets an uninitialized field', () => { + const form = new FormApi({ + defaultValues: { + availableFor: 'longStay', + } as { availableFor: string; fees?: number }, + }) + form.mount() + + // `fees` is rendered conditionally and has not been mounted yet, so its + // meta is created for the first time by this call. + form.setFieldValue('fees', 1) + + const meta = form.getFieldMeta('fees') + + // Every documented meta field must be present (not `undefined`), matching + // the meta of a field that has been mounted normally. + expect(meta).toMatchObject({ + isValidating: false, + isBlurred: false, + // `setFieldValue` marks the newly created meta as touched and dirty. + isTouched: true, + isDirty: true, + errors: [], + errorSourceMap: {}, + }) + expect(meta?.isValidating).not.toBeUndefined() + expect(meta?.isBlurred).not.toBeUndefined() + expect(meta?.errorSourceMap).not.toBeUndefined() + }) + it('should reset with provided custom default values', () => { const defaultValues = { name: 'test',