vuejs-tips / vue-the-mask

Tiny (<2k gzipped) and dependency free mask input for Vue.js
https://vuejs-tips.github.io/vue-the-mask/
1.72k stars 212 forks source link

Allow undefined to be passed to v-mask directive #82

Open Kasheftin opened 6 years ago

Kasheftin commented 6 years ago

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.

SohrabZ commented 6 years ago

I have the very same issue.

bart-1990 commented 6 years ago

I'm also facing this issue.

ayrtonvwf commented 5 years ago

Same issue. PR #34 should resolve this issue.

illjah42 commented 5 years ago

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 : '*'"
adriandmitroca commented 5 years ago

Same issue.

tarponjargon commented 5 years ago

same

samuelcust commented 5 years ago

Same

lwxbr commented 5 years ago

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.

samuelcust commented 5 years ago

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!

lwxbr commented 5 years ago

@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.

david-mart commented 4 years ago
<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
Alberghini commented 4 years ago

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

KelvynCarbone commented 4 years ago

The directive has a property masked, example:

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

rsornellas commented 4 years ago

same here

gvonderau commented 4 years ago

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.

MayaraRMA commented 4 years ago

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.

educkf commented 4 years ago

Awesome solution, @MayaraRMA 👏👏👏

Igoohd-zz commented 3 years ago

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?

educkf commented 3 years ago

@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.

Igoohd-zz commented 3 years ago

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

educkf commented 3 years ago

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

M-erb commented 2 years ago

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);
    }
  },
mod7ex commented 2 years ago

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);
  },
};
JeffJassky commented 1 year ago

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

Hallyson34 commented 6 months ago

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