Reputation: 734
I have a form with a phone number input and I would like the number formatting to change to a relevant telephone number format as the user is actively typing in the number. Can someone kindly guide me as to how this can be achieved in JS and vue 3, please?
AppointmentForm.vue - this is my main component
<div class="form-control">
<label class="form-input" for="telNumber">Telefoonnummer (optioneel)</label>
<input v-model="telNumber"
:class="{ 'input-error': numberError }"
@input="numberFormatting"
id="telNumber"
type="tel"
placeholder="Vul uw telefoonnummer in"
class="field-input">
<div v-if="numberError" class="validation-error">
<span class="error-message">Voer een bestaand nummer in</span>
</div>
</div>
In my script I run a basic validation function to validate the number, but it might not be really relevant for this scenario.
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();
}
}
Upvotes: 2
Views: 2557
Reputation: 17160
I solved it using maska
by putting a watcher on the field 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>
Just use your input as normal and add the watcher.
Upvotes: 0
Reputation: 35714
You can use a vue3 compatible 3rd party library called maska
I've tried implementing such things myself, but in the interest of time and functionality, I've found it easier to just use that library.
If you want to make your own solution, the trick is on input/change to replace the value with a value that you parse with a regex match/substitution. (it's in vanilla js, but easily updated for vue3)
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{
min-width: 260px;
display:block;
border-radius:4px;
border: 2px solid #3366FF;
padding: 8px 6px;
margin: 0 0.2rem 0.8rem 0;
box-sizing: border-box;
}
input.err {
border-color: red;
}
<input id="phone" placeholder="#(###) ### ####">
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')
.field-input{display:block; border: 2px solid #CCC; padding:0.4em;border-radius:0.4em}.input-error{border-color:tomato} .error-message{color:tomato}
<script src="https://unpkg.com/[email protected]/dist/vue.global.prod.js"></script>
<div id="app">
<div class="form-control">
<label class="form-input" for="telNumber">Telefoonnummer (optioneel)</label>
<input v-model="telNumber"
:class="{ 'input-error': numberError }"
@input="numberFormatting"
id="telNumber"
type="tel"
placeholder="Vul uw telefoonnummer in"
class="field-input">
<div v-if="numberError" class="validation-error">
<span class="error-message">Voer een bestaand nummer in</span>
</div>
</div>
</div>
Upvotes: 2