Skip to content

Commit

Permalink
fix: prevent reset from wiping validators in fieldMeta (#674)
Browse files Browse the repository at this point in the history
  • Loading branch information
luishcastroc committed Apr 16, 2024
1 parent c0ee012 commit 18d3810
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 6 deletions.
1 change: 1 addition & 0 deletions examples/angular/simple/src/app/app.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import type {
<button type="submit" [disabled]="!canSubmit()">
{{ isSubmitting() ? '...' : 'Submit' }}
</button>
<button type="reset" (click)="form.reset()">Reset</button>
</form>
`,
})
Expand Down
15 changes: 10 additions & 5 deletions examples/react/simple/src/index.tsx
Original file line number Diff line number Diff line change
@@ -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<any, any, any, any> }) {
return (
Expand Down Expand Up @@ -94,9 +94,14 @@ export default function App() {
<form.Subscribe
selector={(state) => [state.canSubmit, state.isSubmitting]}
children={([canSubmit, isSubmitting]) => (
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? '...' : 'Submit'}
</button>
<>
<button type="submit" disabled={!canSubmit}>
{isSubmitting ? '...' : 'Submit'}
</button>
<button type="reset" onClick={() => form.reset()}>
Reset
</button>
</>
)}
/>
</form>
Expand Down
27 changes: 26 additions & 1 deletion packages/form-core/src/FormApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<ValidationError[]>[] = [] as any
Expand Down Expand Up @@ -622,6 +626,27 @@ export class FormApi<
})
}

resetFieldMeta = <TField extends DeepKeys<TFormData>>(
fieldMeta: Record<TField, FieldMeta>,
): Record<TField, FieldMeta> => {
return Object.keys(fieldMeta).reduce(
(acc: Record<TField, FieldMeta>, key) => {
const fieldKey = key as TField
acc[fieldKey] = {
isValidating: false,
isTouched: false,
isDirty: false,
isPristine: true,
touchedErrors: [],
errors: [],
errorMap: {},
}
return acc
},
{} as Record<TField, FieldMeta>,
)
}

setFieldValue = <TField extends DeepKeys<TFormData>>(
field: TField,
updater: Updater<DeepValue<TFormData, TField>>,
Expand Down
64 changes: 64 additions & 0 deletions packages/form-core/src/tests/FormApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: {
Expand Down

0 comments on commit 18d3810

Please sign in to comment.