Skip to content

fix(hooks): async validators now actually run - #90

Merged
colorpulse6 merged 9 commits into
mainfrom
fix/async-validation-dispatch
Jun 11, 2026
Merged

fix(hooks): async validators now actually run#90
colorpulse6 merged 9 commits into
mainfrom
fix/async-validation-dispatch

Conversation

@colorpulse6

Copy link
Copy Markdown
Owner

The bug

el-form's async validators (onChangeAsync/onBlurAsync/onSubmitAsync, field- and form-level, *AsyncDebounceMs/asyncDebounceMs/asyncAlways) were silent no-ops — the hooks layer always built the engine validation event with isAsync: false, so the engine resolved the sync key and never invoked the async validator. The el-form-core engine already handles async correctly; this is a hooks-only fix.

The fix

  • utils/validation.tsvalidateFieldAsync / validateFormAsync / hasAsyncValidator / shouldRunAsync (dispatch isAsync: true).
  • useForm.ts — onChange/onBlur run a non-blocking async pass: sync-first (gated; honors asyncAlways), stale-guarded, clear-on-success.
  • submitOperations.ts / errorManagement.tssubmit()/handleSubmit/trigger() await async (blocking); a failing async rule blocks submission; trigger('field') runs all the field's configured async keys.
  • Docs + changeset; corrected stale {isValid,errors} async examples.

Verification

  • el-form-react-hooks suite 142 pass; lint clean; pnpm build:packages + DTS; docs build clean.
  • TDD throughout; final comprehensive review confirmed the core wiring correct (its two merge-gate findings fixed + tests added).

⚠️ Behavior change (patch, documented in changeset)

Forms that configured async validators (and silently passed) will now actually validate async and can gate submit. Intended fix for a previously-dead documented feature.

Known follow-ups (non-blocking)

Form-level bare-string change/blur async is swallowed (use { fields: {...} }); asyncAlways applies only pre-submit; a core quirk where form async returning { fields: {} } reads as invalid; submit-path duplication.

🤖 Generated with Claude Code

colorpulse6 and others added 9 commits June 10, 2026 16:46
el-form async validators (onChangeAsync etc.) never run — hooks always
dispatch isAsync:false. Fix is hooks-only: add an async pass (sync-first,
async only if sync passes; non-blocking onChange/onBlur, blocking submit/
trigger; stale-guarded). Engine already handles async + debounce. Patch bump.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
6 TDD tasks: manager async methods+gate (unit), onChange/onBlur non-blocking
async pass, sync-first/asyncAlways/stale-guard, blocking submit+trigger, docs
+changeset, verification.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add hasAsyncValidator, shouldRunAsync, validateFieldAsync, and validateFormAsync
to ValidationManager so the hooks layer can dispatch isAsync:true events to the
engine, which resolves the ${type}Async validator keys.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…first)

Wire a non-blocking async pass into the register onChange/onBlur handlers so
onChangeAsync/onBlurAsync fieldValidators actually execute and surface errors.
Async pass fires only when shouldRunAsync() approves (hasAsyncValidator +
syncPassed-or-asyncAlways), with a stale-value guard to drop superseded results.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Update async-validation.md and concepts/validation.md to reflect that
onChangeAsync/onBlurAsync/onSubmitAsync, asyncDebounceMs, and asyncAlways
now run instead of being silent no-ops. Fix stale field-validator examples
that used the wrong { isValid, errors } return shape (correct shape is
string | undefined). Add changelog unreleased entry and changeset.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
…rror clear; add async submit/trigger tests

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@qodo-code-review

Copy link
Copy Markdown

Qodo reviews are paused for this user.

Troubleshooting steps vary by plan Learn more →

On a Teams plan?
Reviews resume once this user has a paid seat and their Git account is linked in Qodo.
Link Git account →

Using GitHub Enterprise Server, GitLab Self-Managed, or Bitbucket Data Center?
These require an Enterprise plan - Contact us
Contact us →

@github-actions github-actions Bot added the ready to publish This PR contains a Changeset and is ready to be published. label Jun 11, 2026
@colorpulse6
colorpulse6 merged commit 36c91fc into main Jun 11, 2026
8 checks passed
@colorpulse6
colorpulse6 deleted the fix/async-validation-dispatch branch June 11, 2026 05:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

ready to publish This PR contains a Changeset and is ready to be published.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant