Skip to content

Commit

Permalink
do not re-validate on blur if already validated
Browse files Browse the repository at this point in the history
In testing #76 in
GitHub.com, we discovered cases where input would be re-validated
on blur even if the input had not changed. This PR updates our
valid and invalid code paths to only validate on blur if the input
has not otherwise been already validated.
  • Loading branch information
joelhawksley committed Dec 11, 2024
1 parent 32051d9 commit 7948ebc
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 2 deletions.
13 changes: 11 additions & 2 deletions src/auto-check-element.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,12 +214,19 @@ function handleChange(checker: () => void, event: Event) {
const autoCheckElement = input.closest('auto-check')
if (!(autoCheckElement instanceof AutoCheckElement)) return

if (event.type === 'input') {
autoCheckElement.setAttribute('dirty', '')
}

if (input.value.length === 0) return

if (
(event.type !== 'blur' && !autoCheckElement.onlyValidateOnBlur) || // Existing default behavior
(event.type === 'blur' && autoCheckElement.onlyValidateOnBlur) || // Only validate on blur if only-validate-on-blur is set
(autoCheckElement.onlyValidateOnBlur && autoCheckElement.validateOnKeystroke) // Only validate on key inputs in only-validate-on-blur mode if validate-on-keystroke is set (when input is invalid)
(event.type === 'blur' &&
autoCheckElement.onlyValidateOnBlur &&
!autoCheckElement.validateOnKeystroke &&
autoCheckElement.hasAttribute('dirty')) || // Only validate on blur if only-validate-on-blur is set, input is dirty, and input is not current validating on keystroke
(event.type === 'input' && autoCheckElement.onlyValidateOnBlur && autoCheckElement.validateOnKeystroke) // Only validate on key inputs in only-validate-on-blur mode if validate-on-keystroke is set (when input is invalid)
) {
setLoadingState(event)
checker()
Expand Down Expand Up @@ -326,6 +333,8 @@ async function check(autoCheckElement: AutoCheckElement) {

state.controller = makeAbortController()

autoCheckElement.removeAttribute('dirty')

try {
const response = await fetchWithNetworkEvents(autoCheckElement, url.toString(), {
credentials: 'same-origin',
Expand Down
29 changes: 29 additions & 0 deletions test/auto-check.js
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,18 @@ describe('auto-check element', function () {
assert.deepEqual(events, ['auto-check-start'])
})

it('does not emit on blur if input has not changed after initial blur', async function () {
const events = []
input.addEventListener('auto-check-start', event => events.push(event.type))
triggerInput(input, 'hub')
triggerBlur(input)

await once(input, 'auto-check-complete')
triggerBlur(input)

assert.deepEqual(events, ['auto-check-start'])
})

it('emits on input change if input is invalid after blur', async function () {
const events = []
input.addEventListener('auto-check-start', event => events.push(event.type))
Expand All @@ -74,6 +86,23 @@ describe('auto-check element', function () {
assert.deepEqual(events, ['auto-check-start', 'auto-check-start', 'auto-check-start'])
})

it('does not emit on blur if input is invalid', async function () {
const events = []
input.addEventListener('auto-check-start', event => events.push(event.type))

checker.src = '/fail'
triggerInput(input, 'hub')
triggerBlur(input)
await once(input, 'auto-check-complete')

triggerInput(input, 'hub2')
triggerBlur(input)

triggerInput(input, 'hub3')

assert.deepEqual(events, ['auto-check-start', 'auto-check-start', 'auto-check-start'])
})

afterEach(function () {
document.body.innerHTML = ''
checker = null
Expand Down

0 comments on commit 7948ebc

Please sign in to comment.