diff --git a/examples/angular/simple/src/app/app.component.ts b/examples/angular/simple/src/app/app.component.ts index e274d60c9..747de7602 100644 --- a/examples/angular/simple/src/app/app.component.ts +++ b/examples/angular/simple/src/app/app.component.ts @@ -55,6 +55,7 @@ import type { + `, }) diff --git a/examples/react/simple/src/index.tsx b/examples/react/simple/src/index.tsx index 3ac204eee..522871585 100644 --- a/examples/react/simple/src/index.tsx +++ b/examples/react/simple/src/index.tsx @@ -1,7 +1,7 @@ +import type { FieldApi } from '@tanstack/react-form' +import { useForm } from '@tanstack/react-form' import * as React from 'react' import { createRoot } from 'react-dom/client' -import { useForm } from '@tanstack/react-form' -import type { FieldApi } from '@tanstack/react-form' function FieldInfo({ field }: { field: FieldApi }) { return ( @@ -94,9 +94,14 @@ export default function App() { [state.canSubmit, state.isSubmitting]} children={([canSubmit, isSubmitting]) => ( - + <> + + + )} /> diff --git a/packages/form-core/src/FormApi.ts b/packages/form-core/src/FormApi.ts index e7d896a5a..733ef4464 100644 --- a/packages/form-core/src/FormApi.ts +++ b/packages/form-core/src/FormApi.ts @@ -335,13 +335,17 @@ export class FormApi< }) } - reset = () => + reset = () => { + const { fieldMeta: currentFieldMeta } = this.state + const fieldMeta = this.resetFieldMeta(currentFieldMeta) this.store.setState(() => getDefaultFormState({ ...(this.options.defaultState as any), values: this.options.defaultValues ?? this.options.defaultState?.values, + fieldMeta, }), ) + } validateAllFields = async (cause: ValidationCause) => { const fieldValidationPromises: Promise[] = [] as any @@ -622,6 +626,27 @@ export class FormApi< }) } + resetFieldMeta = >( + fieldMeta: Record, + ): Record => { + return Object.keys(fieldMeta).reduce( + (acc: Record, key) => { + const fieldKey = key as TField + acc[fieldKey] = { + isValidating: false, + isTouched: false, + isDirty: false, + isPristine: true, + touchedErrors: [], + errors: [], + errorMap: {}, + } + return acc + }, + {} as Record, + ) + } + setFieldValue = >( field: TField, updater: Updater>, diff --git a/packages/form-core/src/tests/FormApi.spec.ts b/packages/form-core/src/tests/FormApi.spec.ts index d0de3527b..2429111b6 100644 --- a/packages/form-core/src/tests/FormApi.spec.ts +++ b/packages/form-core/src/tests/FormApi.spec.ts @@ -192,6 +192,70 @@ describe('form api', () => { }) }) + it('should not wipe validators when resetting', () => { + const form = new FormApi({ + defaultValues: { + name: 'test', + }, + }) + + const field = new FieldApi({ + form, + name: 'name', + validators: { + onChange: ({ value }) => (value.length > 0 ? undefined : 'required'), + }, + }) + + form.mount() + + field.mount() + + field.handleChange('') + + expect(form.state.isFieldsValid).toEqual(false) + expect(form.state.canSubmit).toEqual(false) + + form.reset() + + expect(form.state).toEqual({ + values: { name: 'test' }, + errors: [], + errorMap: {}, + fieldMeta: { + name: { + isValidating: false, + isTouched: false, + isDirty: false, + isPristine: true, + touchedErrors: [], + errors: [], + errorMap: {}, + }, + }, + canSubmit: true, + isFieldsValid: true, + isFieldsValidating: false, + isFormValid: true, + isFormValidating: false, + isSubmitted: false, + isSubmitting: false, + isTouched: false, + isPristine: true, + isDirty: false, + isValid: true, + isValidating: false, + submissionAttempts: 0, + validationMetaMap: { + onChange: undefined, + onBlur: undefined, + onSubmit: undefined, + onMount: undefined, + onServer: undefined, + }, + }) + }) + it("should get a field's value", () => { const form = new FormApi({ defaultValues: {