diff --git a/src/auto-check-element.ts b/src/auto-check-element.ts index 4007a2d..5f076de 100644 --- a/src/auto-check-element.ts +++ b/src/auto-check-element.ts @@ -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() @@ -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', diff --git a/test/auto-check.js b/test/auto-check.js index 81dbff4..5aecd59 100644 --- a/test/auto-check.js +++ b/test/auto-check.js @@ -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)) @@ -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