probil / v-mask

🔡 Tiny input mask library for Vue.js (directive)
https://v-mask-demo.netlify.com
MIT License
904 stars 132 forks source link

Passing function as mask causes infinite loop when used with vee-validate #511

Open zaalbarxx opened 3 years ago

zaalbarxx commented 3 years ago

V-Mask and Vue versions

2.2.4, 2.6.12

Reproduction Link

https://codesandbox.io/s/v-mask-demo-forked-ch575?file=/components/Input.vue

Steps to reproduce

  1. Open the link
  2. Observe the console, input events get continously emitted causing re-renders

What is Expected?

Adding function expression as mask should not trigger input events on every componentUpdated

What is actually happening?

I am not quite sure what exacly happens there, but I noticed that if I remove v-slot (scoped slot) from ValidationObserver then the problem disappears. Not sure why, but seems like v-mask componentUpdated triggers new input event on every component re-render which then gets listened by ValidationObserver which re-renders slotted content and v-mask again triggers input event causing a loop. Is there any specific reason why the componentUpdated method does not compare function results ? I mean this code.

var isMaskChanged = isFunction(value) || maskToString(oldValue) !== maskToString(value);

What is the purpose of marking the mask as changed if isFunction(value) ?

Eternal-Rise commented 3 years ago

Same issue without vee-validate

braunshedd commented 3 years ago

Hiya folks! If you're visiting this in the future, here's how I managed to solve this problem:

You /can not/ use a computed property OR pass a function directly to v-mask. You must use a regular variable, and then update that variable with watch. For example:

<input v-mask='mask' v-model='mymodel' />

 ...

data() {
  return {
    mymodel: '',
    mask: '',
    currencyMask: createNumberMask({})
  }
}

watch() {
  mymodel(newVal) {
    mask = this.currencyMask(newVal)
  }
}
PhucNguyenDuc commented 5 months ago

Hiya folks! If you're visiting this in the future, here's how I managed to solve this problem:

You /can not/ use a computed property OR pass a function directly to v-mask. You must use a regular variable, and then update that variable with watch. For example:

<input v-mask='mask' v-model='mymodel' />

 ...

data() {
  return {
    mymodel: '',
    mask: '',
    currencyMask: createNumberMask({})
  }
}

watch() {
  mymodel(newVal) {
    mask = this.currencyMask(newVal)
  }
}

This will solve most things but will still trip when using currency mask with decimal, v-mask's parseMask function when processing different type of mask, i.e function, array or string will differs. image Function will be used as is, but with array, if an element is string, it will split into a char array, which will mess with text-mask-addons "caret capture" string https://github.com/text-mask/text-mask/blob/master/addons/src/createNumberMask.js#L137 Our team avoided this issue by filtering out that specific string, which is '[]'.