vue-the-mask icon indicating copy to clipboard operation
vue-the-mask copied to clipboard

Allow undefined to be passed to v-mask directive

Open Kasheftin opened this issue 7 years ago • 25 comments

I widely use form builder in my app. It receives a config like [{key: name, type: string}, {key: birth, type: date},...] and builds a form. I want to add mask property to text input that related to vue-the-mask directive to be able to specify it in the config like that: {key: ssn, mask: {mask: '###-##-##', tokens: {...}}}.

The issue is that it's optional property, it's defined for ssn but it's not defined for user name field.

Currently I have to add it like that:

<input v-if="option.mask" v-mask="option.mask" ...a lot of other options here...>
<input v-else ...a lot of the same options here...>

That's because v-mask="undefined" throws an error. I would suggest to allow undefined or null option to be passed as v-mask directive argument, and if it's passed just do not apply v-mask directive at all.

Kasheftin avatar Aug 13 '18 08:08 Kasheftin

I have the very same issue.

SohrabZ avatar Sep 08 '18 18:09 SohrabZ

I'm also facing this issue.

bart-1990 avatar Sep 24 '18 09:09 bart-1990

Same issue. PR #34 should resolve this issue.

ayrtonvwf avatar Oct 03 '18 23:10 ayrtonvwf

Same issue! Very cool and simple directive, but usage inside own components becomes tricky, sometimes a lot of code on input field should be duplicated because we can`t just use something like

v-mask="mask ? mask : false"

Maybe the simpliest way to resolve this is to add a token

'*': /./

then we can use it like

v-mask="mask ? mask : '*'"

illjah42 avatar Jan 17 '19 17:01 illjah42

Same issue.

adriandmitroca avatar May 09 '19 15:05 adriandmitroca

same

tarponjargon avatar May 24 '19 15:05 tarponjargon

Same

samuelcust avatar Jul 10 '19 20:07 samuelcust

The developer needs to implement this or implement a wild card mask.

The solution I found is:


import {mask} from 'vue-the-mask';

export default {
  directives: {
             mask: {
                ...mask,
                tokens: {
                  ...mask.tokens,
                     '*': /./,
                 }
            },
     
        },
...
}

And in directive v-mask="*", that solves the problem. Thanks, @illjah42 for the suggestion.

lwxbr avatar Jul 19 '19 19:07 lwxbr

The developer needs to implement this or implement a wild card mask.

The solution I found is:

import {mask} from 'vue-the-mask';

export default {
  directives: {
             mask: {
                ...mask,
                tokens: {
                  ...mask.tokens,
                     '*': /./,
                 }
            },
     
        },
...
}

And in directive v-mask="*", that solves the problem. Thanks, @illjah42 for the suggestion.

Nice!

samuelcust avatar Jul 19 '19 20:07 samuelcust

@samuelcust, sorry for post wrong solution. I thought the developer implemented the directive using directive properties. Like in this doc: https://br.vuejs.org/v2/guide/custom-directive.html. Reading the code. I think the hole is more deep than I thought. Really, there's no way to extend that directive to achieve that. I did add new tokens to the default ones but the problem is the length of the mask, that is hard to change.

lwxbr avatar Jul 19 '19 20:07 lwxbr

<template>
  <div class="input-with-label" :class="{ focused }">
    <el-input
      size="mini"
      :placeholder="label"
      v-model="param"
      v-mask="mask || nomask"
      :masked="!!mask"
    />
  </div>
</template>

<script>
export default {
  data() {
    return {
      focused: false,
      nomask: {
        mask: '*'.repeat(255),
        tokens: {
          '*': { pattern: /./ }
        }
      }
    }
  },
  props: ['label', 'value', 'mask'],
}
</script>

Here's my hacky solution to the character length issue

david-mart avatar Nov 08 '19 23:11 david-mart

Im using v-mask plugin

This solved my problem: <input v-mask="field.mask ? field.mask : continuousMask(model[field.model])" />

And then I added a method like this:

continuousMask(model){
     let mask = ""
     if(model && model.length){
         for(let i = 0; i < model.length; i++){
             mask += 'X'
         }
     }
     return mask
}

The character "X" means "any symbol", which I think is the same as having no mask

This way the mask will be always the same length as the input value and accept any symbol. This is the way I've found to work like it doesn't have a mask

Anyway, this is a workaround and would be nice if the plugin accepted false to have no mask

Please test before using

Alberghini avatar Nov 30 '19 20:11 Alberghini

The directive has a property masked, example:

v-mask="field.mask" :masked="field.mask ? true : false"

KelvynCarbone avatar Feb 03 '20 20:02 KelvynCarbone

same here

rsornellas avatar Feb 13 '20 18:02 rsornellas

The directive has a property masked, example:

v-mask="field.mask" :masked="field.mask ? true : false"

:masked true / false is how you want the input returned, either in it's Masked or Raw (unmasked) format. In both cases, the mask is still applied to the input field.

gvonderau avatar Feb 20 '20 13:02 gvonderau

I'm using this:

directives: {
    mask: (el, binding) => {
      if (!binding.value) return;
      mask(el, binding);
    }
  },

but I don't know if is the best way.

MayaraRMA avatar Jul 20 '20 20:07 MayaraRMA

Awesome solution, @MayaraRMA 👏👏👏

educkf avatar Sep 30 '20 06:09 educkf

I'm using this:

directives: {
    mask: (el, binding) => {
      if (!binding.value) return;
      mask(el, binding);
    }
  },

but I don't know if is the best way.

Can you show more of the code?

Igoohd-zz avatar Oct 13 '20 14:10 Igoohd-zz

@Igoohd I made like this:

  1. created a helper file with this code:
import { mask } from "vue-the-mask";

export const applyMask = {
	bind(el, binding) {
		if (binding.value && binding.value !== "") {
			mask(el, binding);
		}
	},
	unbind() {},
};
  1. then on the component I needed it, i used it like this:
<template>
     <input v-mask="maskTemplate" />
</template>

<script>
import { applyMask as _mask } from "@/helpers";
export default {
	name: "InputField",
	directives: {
		mask: _mask,
	},
        props: {
                maskTemplate: {
			type: String,
			default: "",
		},
        }
}
</script>

So if maskTemplate prop is empty, it don't apply vue-the-mask, only if maskTemplate prop has any value.

educkf avatar Oct 13 '20 14:10 educkf

@Igoohd I made like this:

  1. created a helper file with this code:
import { mask } from "vue-the-mask";

export const applyMask = {
	bind(el, binding) {
		if (binding.value && binding.value !== "") {
			mask(el, binding);
		}
	},
	unbind() {},
};
  1. then on the component I needed it, i used it like this:
<template>
     <input v-mask="maskTemplate" />
</template>

<script>
import { applyMask as _mask } from "@/helpers";
export default {
	name: "InputField",
	directives: {
		mask: _mask,
	},
        props: {
                maskTemplate: {
			type: String,
			default: "",
		},
        }
}
</script>

So if maskTemplate prop is empty, it don't apply vue-the-mask, only if maskTemplate prop has any value.

<script>
import { mask } from 'vue-the-mask'

export const applyMask = {
    bind (el, binding) {
        if (binding.value && binding.value !== '') {
            mask(el, binding)
        }
    },
    unbind () {}
}
</script>

Your "Helpers" is only with tag script?

Igoohd-zz avatar Oct 13 '20 15:10 Igoohd-zz

It is a plain .js file, to add simple functions, and not a .vue file. This is the link to the file: https://github.com/educkf/senior-frontend-test/blob/master/helpers/index.js

educkf avatar Oct 13 '20 17:10 educkf

This worked perfect for me with Vue3! Thank you @MayaraRMA for such an elegant solution even 2 years later!

Edit, adding solution here as well:

  directives: {
    mask: (el, binding) => {
      if (!binding.value) return;
      mask(el, binding);
    }
  },

M-erb avatar Apr 21 '22 21:04 M-erb

I think the right and the safest way is to do it programmatically, in my case i use Maska almost same as what you guys use

so in my custom input in a setup script :

const inputRef = ref(); // element refrence

const maskInput = (v) => {
  if (props.mask) return mask(v, props.mask);
  return v;
};

const handelInput = (e) => {
  if (e.inputType === 'deleteContentBackward') {
    emit('update:modelValue', e.target.value);
  } else {
    const v = maskInput(e.target.value);
    emit('update:modelValue', v);
    inputRef.value.value = v;
  }
};

const vMask = {
  updated(el, binding) {
    console.log(binding.vlaue);
  },
};

mod7ex avatar Aug 24 '22 15:08 mod7ex

The solutions here don't allow for the dynamic masks. If I have a mask set, then set it to undefined, it stays masked.

JeffJassky avatar Sep 25 '23 20:09 JeffJassky

My solution for this is: v-mask="option.mask ? option.mask : 'X'.repeat(255)" X can be changed for another pattern token of v-mask, like these:

Tokens '#': {pattern: /\d/}, 'X': {pattern: /[0-9a-zA-Z]/}, 'S': {pattern: /[a-zA-Z]/}, 'A': {pattern: /[a-zA-Z]/, transform: v => v.toLocaleUpperCase()}, 'a': {pattern: /[a-zA-Z]/, transform: v => v.toLocaleLowerCase()},

Edit: Doesn't allow special characters like space :v

Hallyson34 avatar Mar 28 '24 20:03 Hallyson34