Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/form-core/src/FormApi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1544,22 +1544,26 @@ export class FormApi<
}

/**
* Validates all fields using the correct handlers for a given validation cause.
* Validates all fields according to the FIELD level validators.
* This will ignore FORM level validators, use form.validate({ValidationCause}) for a complete validation
*/
validateAllFields = async (cause: ValidationCause) => {
const fieldValidationPromises: Promise<ValidationError[]>[] = [] as any

batch(() => {
void (Object.values(this.fieldInfo) as FieldInfo<any>[]).forEach(
(field) => {
if (!field.instance) return
const fieldInstance = field.instance

// Validate the field
fieldValidationPromises.push(
// Remember, `validate` is either a sync operation or a promise
Promise.resolve().then(() =>
fieldInstance.validate(cause, { skipFormValidation: true }),
),
)

// If any fields are not touched
if (!field.instance.state.meta.isTouched) {
// Mark them as touched
Expand Down
32 changes: 26 additions & 6 deletions packages/form-core/tests/FormApi.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1945,7 +1945,7 @@ describe('form api', () => {
).toBeUndefined()
})

it('should validate all fields consistently', async () => {
it('should validate all fields consistently - field level onChange validators', async () => {
const form = new FormApi({
defaultValues: {
firstName: '',
Expand All @@ -1957,18 +1957,38 @@ describe('form api', () => {
form,
name: 'firstName',
validators: {
onChange: ({ value }) =>
value.length > 0 ? undefined : 'first name is required',
onChange: ({ value }) => (value.length > 0 ? undefined : 'is required'),
},
})

form.mount()
field.mount()

await form.validateAllFields('change')
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
await form.validateAllFields('change')
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
expect(field.getMeta().errorMap.onChange).toEqual('is required')
})

it('should validate all fields consistently - field level onSubmit validators', async () => {
const form = new FormApi({
defaultValues: {
firstName: '',
lastName: '',
},
})

const field = new FieldApi({
form,
name: 'firstName',
validators: {
onSubmit: ({ value }) => (value.length > 0 ? undefined : 'is required'),
},
})

form.mount()
field.mount()

await form.validateAllFields('submit')
expect(field.getMeta().errorMap.onSubmit).toEqual('is required')
})

it('should validate a single field consistently if touched', async () => {
Expand Down
Loading