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

Encountering a TypeScript error while calling a Vue lifecycle hook method

Struggling to call a method in a Vue root component from a lifecycle method in typescript? See below for a simple example that showcases this issue: import Vue from "vue"; class Game { a: number; b: number; constructor() { this.a = 3; ...

Why is my node.js react app failing to detect the index.html file?

Take a look at the app here: git repository The issue I'm facing is that index.html doesn't seem to be properly linked, resulting in: 1) The website not being responsive for mobile devices 2) Lack of a favicon Can you spot any obvious mistak ...

What is causing this issue? Error: [$compile:nonassign] The expression 'undefined' cannot be assigned! AngularJS 1.5

I'm currently working on developing a component to post "Tweets" on my personal website. However, I am facing an issue where I cannot input any text into the textarea. Below is an image showcasing the error: Please review my code in the file "editor ...

Creating a Login Form with Node.js and MongoDB

Currently, I am working on a node.js application that is connected to a remote mongoDB server. Inside the database are specific custom codes that have been created and shared with selected users. The main objective is to restrict access to the rest of the ...

Creating a PDF document with multiple pages using a PHP loop, integrating with AJAX, and utilizing the m

Looking for assistance with a plugin development project involving PDF generation using AJAX. The challenge lies in generating multiple PDFs for each user within a loop. The goal is to create PDFs with multiple pages for individual users. If that's n ...

Toggle visibility of column data on button click in a Vue and Laravel application

I'm struggling with a table setup where each row contains a 'show details' button. Inside the table, there is another div stacked, and I want to display the table in the specific column when the button is clicked. However, I'm having di ...

Real-time File Updates Display with Node.js and Express.js

Seeking guidance on whether there is a Node module available to utilize the Express module for displaying real-time updates in the browser using data from a file. I have a regularly updated .csv file and I am looking to showcase these updates instantly on ...

Remove the color options from the Material UI theme

Can certain color types be excluded from the MUI palette in MUI v5? For example, can background and error colors be removed, allowing only colors defined in a custom theme file to be used? I attempted using 'never' but it did not provide a solut ...

Using nested ternary operations in React can cause issues with accessing local variables

Note: I encountered an issue where the extra curly braces around the first ternary result did not solve my initial problem. I replaced them with parentheses. Josep's suggestion to use getTime required me to equate the dates. The Date().setHours(0, 0, ...

JavaScript and jQuery are lightning fast, especially when the page is reloaded

I am currently working on a responsive website that uses liquid layouts. I have encountered challenges when incorporating images in the design, especially when dealing with different browsers like IE, Firefox, and Chrome. Recently, I faced another issue w ...

Navigating Angular: Discovering Route Challenges in Less Than an Hour

Can someone take a look at my code and help me out? I'm trying to learn Angular.js by following the popular Angular.js in 60 minutes video tutorial, but it seems like things have been updated since then. I'm having trouble getting my routes to wo ...

When using mongoose, is it possible to add a new item and retrieve the updated array in one endpoint?

My API endpoint for the post operation query using mongoose is not returning the updated array after adding a new item. I have been struggling with this issue for 3 days without any success. Any help would be greatly appreciated. router.post("/:spot ...

Ways to navigate private property using the App Component in Angular 4

I have successfully implemented code in my app component to retrieve the current URL and display it in app.component.html. app.component.ts import { Component } from '@angular/core'; import { Router } from '@angular/router'; @Compone ...

Failure encountered when attempting to load JSON data into datalist

I've been trying to incorporate inputs into a datalist in two different ways. However, I've encountered an issue with the first method not working properly. --> Check it out on bootlply var dataList = document.getElementById('json-datalist ...

What is the reason behind this strange alert coming from Vue / Vuetify / Vite?

Currently, I am setting up an array of Vuetify 'chips' that have the ability to drag data from one chip to another: <v-container id="endgrid" style="max-width: 300px; position: relative;"> <v-row v-for="(row,r) ...

Webpage video stalling due to buffering

Currently, I am developing personalized video controls and have integrated a @progress event to monitor the video buffering progress and adjust the width of a progress bar div: <video @progress="videoBuffer($event)"> videoBuffer(e) { if ...

Filter a nested array in AngularJS and retrieve the parent object as the result

I've recently started experimenting with AngularJS to create checkbox filters for my wine store. Here is an example of an item in my store: { "id": 17, "name": "Ermelinda Freitas Reserva", "tag_ids": [40, 12, 56, 6, 60], " ...

Switching the checkbox value upon clicking a div element

One challenge I am facing is with a checkbox that saves its value and title in the local storage when clicked. This checkbox is located within a div, and I want the checkbox value to change whenever any part of the div is clicked. Despite my efforts, I hav ...

Utilize and store images based on the individual user's preferences with PlayCanvas

Currently, I am immersed in a PlayCanvas endeavor where I am trying to render specific objects with textures of my choice. The main issue arises when I come across the config.json file in the PlayCanvas build. Within this file, there is a designated path ...

Reactivating a React hook following the execution of a function or within a function in ReactJS

A new react hooks function has been created to retrieve data from an API and display it on the page: function useJobs () { const [jobs, setJobs] = React.useState([]) const [locations, setLocations] = React.useState({}) const [departments, setDepartm ...