Skip to content

Commit e6e3322

Browse files
authored
fix: make validateAllFields more stable (#526)
* fix: make validateAllFields more stable * test: write test for stable validateAllFields functionality
1 parent 10eb5b8 commit e6e3322

File tree

3 files changed

+37
-17
lines changed

3 files changed

+37
-17
lines changed

packages/form-core/src/FieldApi.ts

Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -378,7 +378,7 @@ export class FieldApi<
378378
}
379379

380380
// Needs type cast as eslint errantly believes this is always falsy
381-
let hasError = false as boolean
381+
let hasErrored = false as boolean
382382

383383
this.form.store.batch(() => {
384384
for (const validateObj of validates) {
@@ -393,7 +393,9 @@ export class FieldApi<
393393
[getErrorMapKey(validateObj.cause)]: error,
394394
},
395395
}))
396-
hasError = true
396+
}
397+
if (error) {
398+
hasErrored = true
397399
}
398400
}
399401
})
@@ -406,7 +408,7 @@ export class FieldApi<
406408
if (
407409
this.state.meta.errorMap[submitErrKey] &&
408410
cause !== 'submit' &&
409-
!hasError
411+
!hasErrored
410412
) {
411413
this.setMeta((prev) => ({
412414
...prev,
@@ -418,9 +420,11 @@ export class FieldApi<
418420
}
419421

420422
// If a sync error is encountered for the errorMapKey (eg. onChange), cancel any async validation
421-
if (hasError) {
423+
if (hasErrored) {
422424
this.cancelValidateAsync()
423425
}
426+
427+
return { hasErrored }
424428
}
425429

426430
__leaseValidateAsync = () => {
@@ -552,17 +556,10 @@ export class FieldApi<
552556
this.form.validate(cause)
553557
} catch (_) {}
554558

555-
// Store the previous error for the errorMapKey (eg. onChange, onBlur, onSubmit)
556-
const errorMapKey = getErrorMapKey(cause)
557-
const prevError = this.getMeta().errorMap[errorMapKey]
558-
559559
// Attempt to sync validate first
560-
this.validateSync(value, cause)
561-
562-
// If there is a new error mapped to the errorMapKey (eg. onChange, onBlur, onSubmit), return the errors array, do not attempt async validation
563-
const newError = this.getMeta().errorMap[errorMapKey]
560+
const { hasErrored } = this.validateSync(value, cause)
564561

565-
if (prevError !== newError) {
562+
if (hasErrored) {
566563
if (!this.options.asyncAlways) {
567564
return this.state.meta.errors
568565
}

packages/form-core/src/FormApi.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -256,14 +256,14 @@ export class FormApi<TFormData, ValidatorType> {
256256
Object.values(this.fieldInfo) as FieldInfo<any, ValidatorType>[]
257257
).forEach((field) => {
258258
Object.values(field.instances).forEach((instance) => {
259+
// Validate the field
260+
fieldValidationPromises.push(
261+
Promise.resolve().then(() => instance.validate(cause)),
262+
)
259263
// If any fields are not touched
260264
if (!instance.state.meta.isTouched) {
261265
// Mark them as touched
262266
instance.setMeta((prev) => ({ ...prev, isTouched: true }))
263-
// Validate the field
264-
fieldValidationPromises.push(
265-
Promise.resolve().then(() => instance.validate(cause)),
266-
)
267267
}
268268
})
269269
})

packages/form-core/src/tests/FormApi.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,4 +816,27 @@ describe('form api', () => {
816816
form.state.fieldMeta['firstName'].errorMap['onSubmit'],
817817
).toBeUndefined()
818818
})
819+
820+
it('should validate all fields consistently', async () => {
821+
const form = new FormApi({
822+
defaultValues: {
823+
firstName: '',
824+
lastName: '',
825+
},
826+
})
827+
828+
const field = new FieldApi({
829+
form,
830+
name: 'firstName',
831+
onChange: (v) => (v.length > 0 ? undefined : 'first name is required'),
832+
})
833+
834+
field.mount()
835+
form.mount()
836+
837+
await form.validateAllFields('change')
838+
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
839+
await form.validateAllFields('change')
840+
expect(field.getMeta().errorMap.onChange).toEqual('first name is required')
841+
})
819842
})

0 commit comments

Comments
 (0)