Dynamic Formatting with Vue JS: Enhancing Phone Number Input

I am working on a form that includes a phone number input field, and I want the formatting of the number to change to a standard telephone number format as the user types. Can someone provide guidance on how this can be achieved using JavaScript and Vue 3?

My main component is AppointmentForm.vue

<div class="form-control">
    <label class="form-input" for="telNumber">Telephone Number (optional)</label>
        <input v-model="telNumber" 
        :class="{ 'input-error': numberError }"
        @input="numberFormatting"
        id="telNumber"
        type="tel"
        placeholder="Enter your telephone number"
        class="field-input">
    <div v-if="numberError" class="validation-error">
        <span class="error-message">Please enter a valid number</span>
    </div>
</div>

Although I have a basic validation function in my script to validate the number, it may not be entirely relevant for this specific case.

setup(props) {
    const telNumber = ref("");
    const numberError = ref(false);

    // Run validate form to check whether the data is added
    function validateForm() {
        if (telNumber.value !== '') {
            const numbers = /^[0-9]+$/;
            if(!telNumber.value.match(numbers)) {
                numberError.value = true;
            } else {
               numberError.value = false;
            }
        } else {
            numberError.value = false;
        }
        if (numberError.value) {
            AnalyticsHandler.userSendForm(true);
        } else if (!numberError.value) {    
            sendEmail();
        } 
    }

Answer №1

If you're looking to incorporate phone number formatting in your Vue3 project, consider using the maska library.

In my experience, implementing this feature from scratch can be time-consuming and complex. That's why opting for a pre-built library like Maska is often more efficient.

If you prefer creating your own solution, you can achieve the same functionality by capturing input/change events and manipulating the value using regex substitution. The example provided below demonstrates how to format a phone number in vanilla JavaScript, which can easily be adapted for a Vue3 application:

function formatPhone(str) {
  return str
    .replace(/\D/g, '')
    .replace(/^(\d{1})(\d{3})(\d{3})(\d{4})/g, "$1 ($2) $3 $4")
    .replace(/^(\d{1})(\d{3})(\d{3})(\d*)/g, "$1 ($2) $3 $4")
    .replace(/^(\d{1})(\d{3})(\d{1,3})/g, "$1 ($2) $3")
    .replace(/^(\d{1})(\d{1,3})/g, "$1 ($2")
    .substring(0, 16)
    .trim();
}

document.querySelector("#phone").addEventListener("input",
  function onUpdate(e) {
    var pos = e.target.selectionStart - e.target.value.length;
    var formatted = formatPhone(e.target.value);
    if(formatted.length > 0 && formatted.length < 16) {e.target.classList.add('err')}
    else {e.target.classList.remove('err')}
    e.target.value = formatted;
    e.target.selectionStart = pos+ e.target.value.length;
    e.target.selectionEnd = pos+ e.target.value.length;
  }
)
<input id="phone" placeholder="#(###) ### ####">

Update (vue version)

const formatPhone = (str) => str
  .replace(/\D/g, '')
  .replace(/^(\d{1})(\d{3})(\d{3})(\d{4})/g, "$1 ($2) $3 $4")
  .replace(/^(\d{1})(\d{3})(\d{3})(\d*)/g, "$1 ($2) $3 $4")
  .replace(/^(\d{1})(\d{3})(\d{1,3})/g, "$1 ($2) $3")
  .replace(/^(\d{1})(\d{1,3})/g, "$1 ($2")
  .substring(0, 16)
  .trim();

Vue.createApp({
  data() {
    const numberFormatting = (e)=>telNumber.value = formatPhone(e.target.value);
    const telNumber = Vue.ref('');
    const numberError = Vue.computed(()=>telNumber.value.length > 0 && telNumber.value.length < 16)
    return {telNumber, numberError, numberFormatting}
  },
}).mount('#app')
<script src="https://unpkg.com/vue@3/dist/vue.global.prod.js"></script>

<div id="app">
  <div class="form-control">
    <label class="form-input" for="telNumber">Phone Number (optional)</label>
    <input v-model="telNumber" 
           :class="{ 'input-error': numberError }"
           @input="numberFormatting"
           id="telNumber"
           type="tel"
           placeholder="Enter your phone number"
           class="field-input">
    <div v-if="numberError" class="validation-error">
      <span class="error-message">Please enter a valid number</span>
    </div>
  </div>
</div>

Answer №2

To find the solution, I utilized the maska method by setting up a watcher on the field's value:

<script setup>
import { watch } from 'vue';
import { mask } from 'maska';

watch(() => details.value.phone_number, () => {
    details.value.phone_number = mask(details.value.phone_number, '###-###-####');
});
</script>

Simply input your data as you normally would and implement the watcher.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the process for executing Selenium IDE scripts in Selenium RC?

As a newcomer to using the selenium testing tool, I am seeking guidance on running selenium IDE scripts within selenium RC. I would greatly appreciate examples and screenshots to help me better understand the process. ...

Troubleshooting issues with using Laravel's history mode in conjunction with VueJS

Looking to create a seamless web single-page app using Laravel and VueJS but without the annoying "#" in the URL that appears when visiting a new page. Currently, I have: const router = new VueRouter({ mode: 'history', history: false ... ...

Tips for implementing jQuery overlay to display radio buttons in a popup window

Following a tutorial, I created an alert window with radio buttons added for user input. You can view the online demo here. The modified source code with the radio buttons is provided below. Below you'll find where I added the radio buttons and how I ...

Immediately Invoked Function Expression in Javascript

const user = { name: "John", age: 30, lastName: "Smith" } (({name, lastName}) => { console.log(name); console.log(lastName); })(user); An error occurred: {(intermediate value)(intermediate value)(intermediate value)} is not function ...

Element not recognized: <my-company-form-extra> - have you properly registered this component?

I've been attempting to render a component using the is directive <template> <div> <v-tabs v-model="currentTab" fixed-tabs> <v-tab v-for="(item, i) in tabItems" :key="i">{{ item }} < ...

Avoiding the occurrence of moiré patterns when using pixi.js

My goal is to create a zoomable canvas with rectangles arranged in a grid using pixi.js. Despite everything working smoothly, I'm facing heavy moire effects due to the grid. My understanding of pixi.js and webgl is limited, but I suspect that the anti ...

What is the process for updating button text upon clicking in Angular?

To toggle the text based on whether this.isDisabled is set to false or true, you can implement a function that changes it when the button is clicked. I attempted to use this.btn.value, but encountered an error. import { Component } from '@angular/core ...

What is the method for adjusting the width of a v-card based on its height?

I have a changing number of v-cards that are displayed based on their quantity. My goal is to maintain an aspect ratio of 16/9, but only adjust the width. To achieve this, I believe I need to make the width dependent on the height, although I am unsure ho ...

Utilizing System.import with Webpack 2 and React for splitting code and managing nested routes

I followed the instructions from a tutorial article on Modus Create titled Code Splitting for React Router with ES6 Imports to create an app. I made some modifications by adding children routes, resulting in the following router configuration: function er ...

Extracting data on an AngularJS platform by using web scraping techniques

I have been working on an AngularJS application that currently retrieves JSON data from an API using http.get, and it's been working really well. Recently, I've been exploring the idea of passing a URL to a static webpage and scraping the result ...

What is the best way to get the latest props in the midst of an async function?

There's a fascinating open-source project called react-share, where the ShareButton component offers a prop known as beforeOnClick for customization. I've utilized this beforeOnClick to upload images to our CDN before sharing, ensuring that only ...

Utilizing GroupBy in RxJs for an Observable of Objects数组

I am working with entries of type Observable<Event[]>, and they are structured as follows: [{ "_id": 1, "_title": "Test Event 1", "_startDate": "2019-05-29T07:20:00.000Z", "_endDate": "2019-05-29T08:00:00.000Z", "_isAllDay": false }, ...

determining the overall page displacement

I'm working with this code and I need help using the IF condition to check if the total page offset is greater-than 75%. How can I implement that here? function getLocalCoords(elem, ev) { var ox = 0, oy = 0; var first; var pageX, pageY; ...

The button text in Bootstrap 5 is black instead of white as shown in their demo

During the installation of Bootstrap 5, I encountered an issue where many of my buttons are displaying a black font instead of the expected white font as shown in the Bootstrap 5 Documentation For instance, the .btn-primary button on the official Bootstra ...

How can AngularJS apps handle authentication?

Seeking input on user authentication with AngularJS and Zend... I currently have Angular on the client side and Zend on the server side handling authentication successfully. However, I'm looking for best practices and code examples for enhancing the ...

Encountering: Unable to break down the property 'DynamicServerError' of 'serverHooks' as it does not have a defined value

An error has arisen in a Nextjs app with TypeScript, specifically in the line of my react component which can be found here. This is my inaugural package creation and after several trials, I managed to test it successfully in a similar vite and TypeScript ...

What is the best way to include the application version in an Electron project using JavaScript

While attempting to publish an update for my app, I encountered a strange error. Can anyone pinpoint the issue? (Note: Node.js is included) Error Message: Unexpected token < <script> console.log(process); let output = <h2 class="page- ...

The selected option in Bootstrap is displayed twice in the Bootstrap modal

I am facing an issue with Bootstrap Select-box showing multiple times in a bootstrap modal wizard. I have tried various solutions from Stack Overflow but none of them seem to work. A screenshot of the problem can be seen below: Here is the relevant part o ...

What causes the function execution to not be delayed by setTimeout?

function attemptDownloadingWebsite(link) { iframe = document.getElementById('downloadIFrame'); iframe.src = link; setTimeout(removeFile(link), 25000); } This is the remove file function: function removeFile(link){ $.ajax ...

Vue.js custom confirmation component failing to open within v-menu

I am having trouble displaying a confirmation component every time a button in the header is clicked. Currently, it only opens when clicking elements outside of the dropdown using v-menu. App.vue <template> {{isConfirmDialogVisible}} <div cla ...