v-mask icon indicating copy to clipboard operation
v-mask copied to clipboard

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

Open zaalbarxx opened this issue 4 years ago • 3 comments

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) ?

zaalbarxx avatar Jan 25 '21 21:01 zaalbarxx

Same issue without vee-validate

Eternal-Rise avatar Jul 27 '21 14:07 Eternal-Rise

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)
  }
}

braunshedd avatar Aug 19 '21 20:08 braunshedd

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 '[]'.

PhucNguyenDuc avatar Apr 10 '24 06:04 PhucNguyenDuc