From a986b63b10339a4fe8ec77be80e128e89c0ed644 Mon Sep 17 00:00:00 2001 From: Andrew Korshunov Date: Thu, 8 Aug 2024 17:46:19 -0500 Subject: [PATCH] #97 Implemented delayed validation by introducing delayedValidation option --- src/index.ts | 28 +++++++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/index.ts b/src/index.ts index 5b54919..ffa80c1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -422,6 +422,7 @@ export interface ValidationServiceOptions { watch: boolean; root: ParentNode; addNoValidate: boolean; + delayedValidation: boolean } /** @@ -1068,6 +1069,15 @@ export class ValidationService { const cb: ValidationEventCallback = async (event, callback) => { let validate = this.validators[uid]; if (!validate) return true; + + if ( + this.options.delayedValidation && + event && event.type === 'input' && + !input.classList.contains(this.ValidationInputCssClassName) + ) { + // When delayedValidation=true, "input" only takes it back to valid. "Change" can make it invalid. + return; + } this.logger.log('Validating', { event }); try { @@ -1089,9 +1099,19 @@ export class ValidationService { }, this.debounce); }; - const validateEvent = input.dataset.valEvent || input instanceof HTMLSelectElement ? 'change' : 'input'; - input.addEventListener(validateEvent, cb.debounced); - cb.remove = () => input.removeEventListener(validateEvent, cb.debounced); + const validateEvent = input.dataset.valEvent || input instanceof HTMLSelectElement ? 'change' : + (this.options.delayedValidation ? 'input change' : 'input'); + const events = validateEvent.split(' '); + + events.forEach((eventName) => { + input.addEventListener(eventName, cb.debounced); + }); + + cb.remove = () => { + events.forEach((eventName) => { + input.removeEventListener(eventName, cb.debounced); + }); + }; this.inputEvents[uid] = cb; } @@ -1378,12 +1398,14 @@ export class ValidationService { root: document.body, watch: false, addNoValidate: true, + delayedValidation: false, } /** * Load default validation providers and scans the entire document when ready. * @param options.watch If set to true, a MutationObserver will be used to continuously watch for new elements that provide validation directives. * @param options.addNoValidate If set to true (the default), a novalidate attribute will be added to the containing form in validate elements. + * @param options.delayedValidation If set to false (the default), validation happens while user inputs. If set to true, validation happens on blur, unless input is already invalid, in which case it will validate on input to indicate the value is valid as soon as possible. */ bootstrap(options?: Partial) { Object.assign(this.options, options);