diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index af0190c28..579fc18cf 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -747,6 +747,26 @@ export class FormApi< })) } } + } else { + for (const [field] of Object.entries(this.fieldInfo)) { + this.setFieldMeta(field as DeepKeys, (prev) => { + const newErrorMap = prev.errorMap; + + if (prev.isDirty) { + for (const [errorKey] of Object.entries(prev.errorMap)) { + newErrorMap[errorKey as ValidationErrorMapKeys] = undefined + } + } + + return { + ...prev, + errorMap: { + ...prev.errorMap, + [errorMapKey]: undefined, + }, + } + }) + } } if (this.state.errorMap[errorMapKey] !== formError) { @@ -875,7 +895,28 @@ export class FormApi< })) } } + } else { + for (const [field] of Object.entries(this.fieldInfo)) { + this.setFieldMeta(field as DeepKeys, (prev) => { + const newErrorMap = prev.errorMap; + + if (prev.isDirty) { + for (const [errorKey] of Object.entries(prev.errorMap)) { + newErrorMap[errorKey as ValidationErrorMapKeys] = undefined + } + } + + return { + ...prev, + errorMap: { + ...prev.errorMap, + [errorMapKey]: undefined, + }, + } + }) + } } + this.store.setState((prev) => ({ ...prev, errorMap: { diff --git a/packages/zod-form-adapter/tests/FormApi.spec.ts b/packages/zod-form-adapter/tests/FormApi.spec.ts index d2ff390ba..c0f54f92d 100644 --- a/packages/zod-form-adapter/tests/FormApi.spec.ts +++ b/packages/zod-form-adapter/tests/FormApi.spec.ts @@ -184,4 +184,50 @@ describe('zod form api', () => { name0Field.setValue('qwer') expect(name0Field.getMeta().errors).toEqual([]) }) + + it('should clear errors if previously errors were set and now are fixed', () => { + const form = new FormApi({ + defaultValues: { + password: '', + confirmPassword: '', + }, + validatorAdapter: zodValidator(), + validators: { + onChange: z.object({ + password: z.string(), + confirmPassword: z.string(), + }).refine(({ password, confirmPassword }) => password === confirmPassword, { + message: 'Passwords must match', + path: ['password'], + }) + } + }); + form.mount(); + + const field1 = new FieldApi({ + form, + name: 'password', + defaultMeta: { + isTouched: true, + }, + }); + field1.mount(); + + const field2 = new FieldApi({ + form, + name: 'confirmPassword', + defaultMeta: { + isTouched: true, + }, + }); + field2.mount(); + + field1.setValue('password'); + expect(field1.getMeta().errors).toStrictEqual(['Passwords must match']); + expect(form.state.canSubmit).toBe(false); + + field2.setValue('password'); + expect(field2.getMeta().errors).toStrictEqual([]); + expect(form.state.canSubmit).toBe(true); + }) })