Marek Barta
Marek Barta

Reputation: 389

Vue.js aplying phone number format

I'm new to Vue.js and was trying to find a way how to format a phone number in an input field to the desired format. I was able to find an answer here on stackoverflow written in plain javascript but I dont know how to use the regex in Vue.

Solution in javascript

document.getElementById('phone').addEventListener('input', function (e) {
  var x = e.target.value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
  e.target.value = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
});

So my question is how to apply it on this input div? So it allows the user to type only numbers and as he is typing the number is showing in the desired format.

<div contentEditable="true" class="inputDiv"></div>

Example what I would like to achive using vue.js.

document.getElementById('phone').addEventListener('input', function (e) {
  var x = e.target.value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
  e.target.value = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
});
<input type="text" id="phone" placeholder="(555) 555-5555"/>

I was trying to look for an answer which is probably pretty stright forward but since I'm new to Vue I was unable to find anything which would help me to make it work.

Upvotes: 8

Views: 40811

Answers (8)

MemoryGuy
MemoryGuy

Reputation: 49

For those looking not to use another v-model, you can use $input with $event:

            <input 
            ref="input" 
            type="text" 
            v-model="form.name"
            @input="formatPhoneNumber($event)" />

then in script setup:

const form = useForm({
name: '',});

const input = ref();

const formatPhoneNumber = (event) => {
const number = event.target.value.replace(/\D/g, '');
const main = number.match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
event.target.value = !main[2]
    ? main[1]
    : `(${main[1]}) ${main[2]}${main[3] ? '-' + main[3] : ''}`
input.value = event.target.value;
};

One v-model for a form

Upvotes: 0

Alper AKPINAR
Alper AKPINAR

Reputation: 91

let phone_format = function (number) {
    var x = number.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
    if (number.length < 11) {
        number = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3]:'');
    }
    return number;
};

You can use above fnc.

I use like that.

<div class="position-relative">
    <input v-model="aa" style="opacity:0" />
    <div v-html="phone_format(aa)" style="position:absolute;top:0;left:0;width:100%;pointer-events: none;"></div>
</div>

Upvotes: 0

Sergeon
Sergeon

Reputation: 6788

Usually in Vue you handle forms with v-model. In a typical form, you would have maybe a phoneNumber variable in your component and would bind it to the input with v-model:

<template>
  <input name="phone" v-model="phoneNumber" />
</template>

<script>
export default new Vue ({
  data() {
    return {
      phoneNumber: '',
    }
  }
})
</script>

The problem is that v-model does not allow you to change the value dynamically as the user types, so that doesn't work for you.

Instead of binding with v-model, however, you can still provide the value with v-bind and react to user input with v-on. The following snippet would always transform whatever the user writes to mayus:

<template>
  <input name="phone" :value="phoneNumber" @input="handleUserInput" />
</template>

<script>
export default new Vue ({
  data() {
    return {
      phoneNumber: '',
    }
  },
  methods: {
    handleUserInput(input) {
      this.value = input.toUpperCase();
    }
  }
})
</script>

Applying format to the phone number is just a bit more complicated that toUpperCase(), but the idea is the same:

<template>
  <input name="phone" :value="phoneNumber" @input="handleUserInput" />
</template>

<script>
export default new Vue ({
  data() {
    return {
      phoneNumber: '',
    }
  },
  methods: {
    handleUserInput(input) {
      var replacedInput = e.target.value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
      this.value = !replacedInput[2] ? replacedInput[1] : '(' + replacedInput[1] + ') ' + replacedInput[2] + (replacedInput[3] ? '-' + replacedInput[3] : '');
    }
  }
})
</script>

Upvotes: 1

Satyam Pathak
Satyam Pathak

Reputation: 6932

You probably need to have a look at how vue works and have some walk through to get a better understanding.

Their documentation is awesome, you can start from there - https://v2.vuejs.org/v2/guide/

For the question, here is a way you can utilise the framework

new Vue({
  el: "#app",
  data: {
    value: ''
  },
  methods: {
    acceptNumber() {
        var x = this.value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
  this.value = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
    }
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
  <h2>Phone number</h2>
   <input v-model="value" type="text" @input="acceptNumber">
</div>

Upvotes: 19

Alan Spurlock
Alan Spurlock

Reputation: 343

Introducing Vue-The-Mask.

npm install vue-the-mask

In your component

<template>
    <input v-mask="['(###) ###-####']"/>
</template>

<script>
import {mask} from 'vue-the-mask'
export default{
    name: "myComponent",
    directives:{mask}
}
</script>

Upvotes: 2

Ognjen
Ognjen

Reputation: 619

My 5 cents. Imagine you have a phone model, that you wish to apply the formatting to.

 data() {
   return {
     phone_number: null,
   };
 }

Your template would look something like this:

<template>
  <div>
    <input
      type="tel"
      placeholder="(123) 456-7890"
      class="form-control"
      id="input-phone"
      v-model="phone_number"
      maxlength="16"
      @input="enforcePhoneFormat()"
    />
  </div>
</template>

So, on input, you call the enforcePhoneFormat() method, which uses regex and transforms the input, to a following format - (123) 345-6789.

methods: {    
  enforcePhoneFormat() {
    let x = this.phone_number
      .replace(/\D/g, "")
      .match(/(\d{0,3})(\d{0,3})(\d{0,4})/);

    this.phone_number = !x[2]
      ? x[1]
      : "(" + x[1] + ") " + x[2] + (x[3] ? "-" + x[3] : "");
  }
}

To change the preferred format, you would have to change the regex, of course.

Upvotes: 1

Dwain Browne
Dwain Browne

Reputation: 1090

Slight modification to @Satyam Pathak code, to support dynamically passing in property names.

<script>
export default new Vue ({
  data() {
    return {
      objectName: {},
    }
  }
})
</script>

methods:{
formatPhoneNumber(propertyName) {
      var x = this.objectName[propertyName]
                  .replace(/\D/g, "")
                  .match(/(\d{0,3})(\d{0,3})(\d{0,4})/);

      this.objectName[propertyName] = !x[2]
        ? x[1] : "(" + x[1] + ") " + x[2] + (x[3] ? "-" + x[3] : "");
    }
}

Upvotes: 0

N. Djokic
N. Djokic

Reputation: 1046

I would recommend using some of the open source Vue components for telephone input like:

https://github.com/LouisMazel/vue-phone-number-input

or

https://www.npmjs.com/package/vue-tel-input

They are really easy to use and and it will save you a lot as you would waste making your own phone input component.

Upvotes: 0

Related Questions