From 2f177939006052052e6705430084140469142fe0 Mon Sep 17 00:00:00 2001 From: Paul Chavard Date: Tue, 17 Jan 2023 13:38:08 +0100 Subject: [PATCH] feat(autosubmit): data-no-autosubmit can disable only some event types this is useful on inputs with datalist for example where we want to only autosubmit on change --- .../controllers/autosubmit_controller.ts | 55 ++++++++++++++++--- 1 file changed, 48 insertions(+), 7 deletions(-) diff --git a/app/javascript/controllers/autosubmit_controller.ts b/app/javascript/controllers/autosubmit_controller.ts index 7e3ec78e1..fe381e521 100644 --- a/app/javascript/controllers/autosubmit_controller.ts +++ b/app/javascript/controllers/autosubmit_controller.ts @@ -4,10 +4,13 @@ import { isTextInputElement, isDateInputElement } from '@utils'; +import { isFormInputElement } from '@coldwired/utils'; + import { ApplicationController } from './application_controller'; const AUTOSUBMIT_DEBOUNCE_DELAY = 500; const AUTOSUBMIT_DATE_DEBOUNCE_DELAY = 5000; +const AUTOSUBMIT_EVENTS = ['input', 'change', 'blur']; export class AutosubmitController extends ApplicationController { static targets = ['submitter']; @@ -15,7 +18,7 @@ export class AutosubmitController extends ApplicationController { declare readonly submitterTarget: HTMLButtonElement | HTMLInputElement; declare readonly hasSubmitterTarget: boolean; - #dateTimeChangedInputs = new WeakSet(); + #dateTimeChangedInputs = new WeakSet(); connect() { this.on('input', (event) => this.onInput(event)); @@ -24,8 +27,8 @@ export class AutosubmitController extends ApplicationController { } private onChange(event: Event) { - const target = event.target as HTMLInputElement; - if (target.disabled || target.hasAttribute('data-no-autosubmit')) return; + const target = this.findTargetElement(event); + if (!target) return; if ( isSelectElement(target) || @@ -48,8 +51,8 @@ export class AutosubmitController extends ApplicationController { } private onInput(event: Event) { - const target = event.target as HTMLInputElement; - if (target.disabled || target.hasAttribute('data-no-autosubmit')) return; + const target = this.findTargetElement(event); + if (!target) return; if (!isDateInputElement(target) && isTextInputElement(target)) { this.debounce(this.submit, AUTOSUBMIT_DEBOUNCE_DELAY); @@ -57,8 +60,8 @@ export class AutosubmitController extends ApplicationController { } private onBlur(event: Event) { - const target = event.target as HTMLInputElement; - if (target.disabled || target.hasAttribute('data-no-autosubmit')) return; + const target = this.findTargetElement(event); + if (!target) return; if (isDateInputElement(target)) { Promise.resolve().then(() => { @@ -70,6 +73,44 @@ export class AutosubmitController extends ApplicationController { } } + private findTargetElement(event: Event) { + const target = event.target; + if ( + !isFormInputElement(target) || + this.preventAutosubmit(target, event.type) + ) { + return null; + } + return target; + } + + private preventAutosubmit( + target: HTMLElement & { disabled?: boolean }, + type: string + ) { + if (target.disabled) { + return true; + } + const noAutosubmit = this.parseNoAutosubmit( + target.getAttribute('data-no-autosubmit') + ); + if (Array.isArray(noAutosubmit)) { + return noAutosubmit.includes(type); + } + return noAutosubmit; + } + + private parseNoAutosubmit(value?: string | null): boolean | string[] { + if (value == null) { + return false; + } + const eventTypes = value + .split(' ') + .map((token) => token.trim()) + .filter((eventType) => AUTOSUBMIT_EVENTS.includes(eventType)); + return eventTypes.length == 0 ? true : eventTypes; + } + private submit() { const submitter = this.hasSubmitterTarget ? this.submitterTarget : null; const form =