From 359f446d727a9cbe560fbe0ce5eddbbb1eda53d5 Mon Sep 17 00:00:00 2001 From: Alexander Shabunevich Date: Sat, 11 Feb 2023 16:12:15 +0300 Subject: [PATCH] Make directive change async for correct eager mode Fix #133 where eager mask used with v-model --- src/directive.ts | 21 +++++++-------------- src/mask-input.ts | 10 +++++++++- test/components/ChangeValue.vue | 6 +++--- test/directive.test.ts | 7 +++++-- 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/directive.ts b/src/directive.ts index 42225a4..2308944 100644 --- a/src/directive.ts +++ b/src/directive.ts @@ -6,13 +6,11 @@ type MaskaDirective = Directive const masks = new WeakMap() const checkValue = (input: HTMLInputElement): void => { - const value = input.dataset.maskaValue - if ( - (value == null && input.value !== '') || - (value != null && value !== input.value) - ) { - input.dispatchEvent(new CustomEvent('input')) - } + setTimeout(() => { + if (masks.get(input)?.needUpdateValue(input) === true) { + input.dispatchEvent(new CustomEvent('input')) + } + }) } export const vMaska: MaskaDirective = (el, binding) => { @@ -21,10 +19,10 @@ export const vMaska: MaskaDirective = (el, binding) => { if (input == null) return + checkValue(input) + const existed = masks.get(input) if (existed != null) { - checkValue(input) - if (!existed.needUpdateOptions(input, opts)) { return } @@ -49,9 +47,4 @@ export const vMaska: MaskaDirective = (el, binding) => { } masks.set(input, new MaskInput(input, opts)) - - // timeout to process initial v-model value - setTimeout(() => { - checkValue(input) - }) } diff --git a/src/mask-input.ts b/src/mask-input.ts index 616c014..d583b9f 100644 --- a/src/mask-input.ts +++ b/src/mask-input.ts @@ -50,6 +50,15 @@ export class MaskInput { return JSON.stringify(mask.opts) !== JSON.stringify(maskNew.opts) } + needUpdateValue (input: HTMLInputElement): boolean { + const value = input.dataset.maskaValue + + return ( + (value == null && input.value !== '') || + (value != null && value !== input.value) + ) + } + private getMaskOpts (options: MaskInputOptions): MaskOptions { const { onMaska, preProcess, postProcess, ...opts } = options @@ -98,7 +107,6 @@ export class MaskInput { const input = e.target as HTMLInputElement const mask = this.items.get(input) as Mask - const valueOld = input.value const ss = input.selectionStart const se = input.selectionEnd diff --git a/test/components/ChangeValue.vue b/test/components/ChangeValue.vue index c2700c5..cfd0c1c 100644 --- a/test/components/ChangeValue.vue +++ b/test/components/ChangeValue.vue @@ -2,10 +2,10 @@ import { ref } from 'vue' import { vMaska } from '../../src' -const data = ref('123') +const data = ref('1234') diff --git a/test/directive.test.ts b/test/directive.test.ts index d022363..7a73134 100644 --- a/test/directive.test.ts +++ b/test/directive.test.ts @@ -138,17 +138,20 @@ test('custom component', async () => { expect(wrapper.get('div').element.textContent).toBe('1-2') }) +// TODO: find a way to test keyboard input, like backspace after input '567' test('change value', async () => { const wrapper = mount(ChangeValue) const input = wrapper.get('input') await new Promise((r) => setTimeout(r)) - expect(input.element.value).toBe('1-2') + expect(input.element.value).toBe('12-3') await wrapper.get('button').trigger('click') - expect(input.element.value).toBe('3-4') + await new Promise((r) => setTimeout(r)) + + expect(input.element.value).toBe('56-7') }) test('multiple inputs', async () => {