How to format phone number with v-model on VueJs - vue.js

When the phone number is entered, I want it to appear in the input in the format (123) - 456 - 78 - 90. how can I do it?
<template>
<div v-for="about in abouts">
<input type="text" v-model="about.phone">
<input type="text" v-model="about.mail">
</div>
</template>
<script>
export default {
data(){
return{
abouts:[{phone:'',mail:''},{phone:'',mail:''}]
}
}
}
</script>

I solved the problem. If you have the same problem you can use vue-mask package.

const q = (ph) => {
const batches = [3, 3, 2, 2];
const template = '({0}) - {1} - {2} - {3}';
let index = 0, summator = 0;
let data = template;
batches.forEach(x => {
const part = ph.substring(summator, x + summator);
data = data.replace(`{${index}}`, part);
index++;
summator += x;
});
return data;
}
and then include it in your data:
abouts:[{phone:q('1234567890'),mail:''},{phone:'',mail:q('')}]
simple way, working. You can add trimming if phone number smaller than 10 digits

Related

vue data-table server side search next button disabled when less than 10 pages in result

I implemented server side search and pagination with Vue data-table (v-data-table). When I start typing in the search bar, at first with only an 'n' it returns 55 pages, which is correct and I can move through the pages with next/previous button. But when the search is 'ni' and only returns 25 items (it calculates correctly this should be 3 pages) my next button is disabled... see below. Does anybody have an idea of where this goes wrong. I also attached my code starting with the data-table template...
<v-data-table
:headers="headers"
:items="all_items"
:search="search"
height="300px"
:server-items-length="totalPages"
fixed-header
:items-per-page="10"
:page="page"
:options.sync="options"
#update:options="onOptionsChanged"
></v-data-table>
</v-card>
</v-container>
</template>
<script>
import axios from "axios";
export default {
name: "datatable",
mounted() {
axios.get('http://localhost:8080/api/fields?model_id=1').then(response => this.headers = response.data.results)
axios.get('http://localhost:8080/api/freemodelitems?model_id=1').then(response => {
this.totalPages = response.data.count > 10 ? Math.ceil(response.data.count / 10) : 1
this.page = this.options.page
for (let i = 0; i < response.data.results.length; i++) {
this.all_items.push(response.data.results[i].data)
}
})
},
watch: {
search: function (val) {
this.search = val
this.onOptionsChanged(this.options, true)
return val
}
},
methods: {
onOptionsChanged(options, page0=false) {
console.log(page0)
axios.get('http://localhost:8080/api/freemodelitems?model_id=1' +
'&page=' +
(!page0 ? this.options.page : 1) +
'&search=' +
this.search).then(response => {
this.page = !page0 ? this.options.page : 1
this.totalPages = response.data.count > 10 ? Math.ceil(response.data.count / 10) : 1
console.log(this.totalPages)
console.log(this.page)
this.all_items = [];
for (let i = 0; i < response.data.results.length; i++) {
this.all_items.push(response.data.results[i].data)
}
})
},
},
data() {
return {
search: "",
options: {},
headers: [],
all_items: [],
pageSize: 10,
totalPages: 0,
page: 1,
}
},
}
</script>
The problem is :server-items-length="totalPages". You are setting the property with total amount of pages, but you need to set it with total amount of items or remove it all together because the component can calculate the number of pages itself.
Quoted from documentation of prop server-items-length:
Used only when data is provided by a server. Should be set to the total amount of items available on server so that pagination works correctly

Change a dot '.' to a comma ',' and add a zero '0' to a price in react native

I want to change a string in the format of 2.8 to 2,80 in react native
class HomeComponent extends React.Component {
constructor(props) {
super(props);
}
state= {
price : '2.8', // I get it in this format from Mysql
}
render() {
return (
<View>
<TouchableOpacity>
<Text> Price : {this.state.price}</Text>
</TouchableOpacity></View>)}
}
export default HomeComponent;
I thought about using split like this
{this.state.price !== undefined ? this.state.price.split('.') : ''}
But it didn't work
You can call this function with the number/string you want to convert.
price = (e) => {
z = e.toString()
zf = z.split(".")[0]
zs = z.split(".")[1]
if (!zs) zs = "00"
if (zs.length == 1) {
return [zf,zs].join(",") + "0"
} else {
return [zf,zs].join(",")
}
}
Use it as such:
price(2.7) // 2,70
price(100) // 100,00
console.log(price(16.52)) // logs "16,52" to the console
Or in a Vue project:
new Vue({
el: "#app",
data: {
banana: 12.7
},
methods: {
price(e) {
z = e.toString() // to string, in case it's a number
zf = z.split(".")[0]
zs = z.split(".")[1]
if (!zs) zs = "00" // add two zeroes if there's no decimal point
if (zs.length == 1) {
return [zf, zs].join(",") + "0" // add a zero if there's one number
} else {
return [zf, zs].join(",") // return if both are present
}
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<div id="app">
<p>
{{price(banana)}} <!-- banana is an example, you should replace it with the data from your DB -->
</p>
</div>

How do I properly display data from this Vue method?

I'm new to Vue and JS.
Could someone help me understand how can I:
display the data I get from the method shown below
and format the method itself and make it look like a proper Vue method in ES6
Code:
Right now it looks like this and just displays data to console.
[...]
<script>
var d = require('../util/diskinfo')
export default {
data () {
return {
}
},
methods: {
getDrivesList () {
d.getDrives(function(err, aDrives) {
for (var i = 0; i < aDrives.length; i++) {
console.log('Drive ' + aDrives[i].filesystem)
console.log('blocks ' + aDrives[i].blocks)
console.log('used ' + aDrives[i].used)
console.log('available ' + aDrives[i].available)
console.log('capacity ' + aDrives[i].capacity)
console.log('mounted ' + aDrives[i].mounted)
}
})
}
}
}
</script>
I want to display it on the page using a loop. Something like this:
<div v-for="i in aDrives" :key="i.id">
<p>Disk name: {{aDrives[i].mounted}}</p>
<p>Disk size: {{aDrives[i].blocks}}</p>
</div>
There's going to be 2 loops - one in the method and one in the template, which makes it confusing. Should I maybe save it to data () first? I'm not sure how to do it properly.
If I understand well, you will receive an array of data and you want to display it. In this case you don't need to loop in the model and in the template. You will just save array locally and then loop through it once in the template.
I will illustrate some ES6 syntax as well in my example:
<template>
<div v-for="driver in drivers">
<p> {{ driver.mounted }} </p>
... display all the data here
</div>
</template>
<script>
import d from '../util/diskinfo'
export default {
data () {
return {
drivers: []
}
},
methods: {
getDrivesList () {
d.getDrives((err, aDrives) => (this.drivers = aDrivers))
}
}
}
</script>

How to separate in vue.js entered value and displayed value in input[type=text]?

Example:
<span class='prefix'>+{{ prefix }}</span>
<input type='tel' v-model='phone'>
What should be displayed
When phone === '790012345678', it is actually
prefix = '7'
phone = '90012345678'
And displayed accordingly
<span class='prefix'>+7</span>
<input type='tel' value='90012345678'>
When user removes value from input, prefix is removed too.
Problem (jsfiddle http://jsfiddle.net/4qqza69k/48/)
I use watcher for `phone`.
When user changes something inside `input` watcher must update value for `phone`, but this way it is triggered again and it receives updated (incorrect) value.
Scenarios:
Phone equals 7-100-200-30-40
prefix = +7, phone = 1002003040
Phone equals 7
prefix = +7, phone = ''
Phone equals 7123
prefix = +7, phone = 123
Phone is empty
prefix = '', phone = ''
Problem: how to exclude prefix from input without triggering updates?
I think you need to rewrite v-model into more explicit v-on + v-bind pair and listen to input for a phone number, while calculating prefix and the rest part separately:
new Vue({
el: '#app',
data: {
prefix: '',
phone: '', // full phone number
},
methods: {
handleInput: function(e) {
if (e.target.value === '') this.prefix = '';
if (this.prefix !== '') {
this.phone = this.prefix + e.target.value;
} else {
const v = e.target.value;
this.phone = v;
this.prefix = v.slice(0,1);
}
}
},
computed: {
withoutPrefix: function() {
return (this.prefix !== '') ? this.phone.slice(1) : ''
}
}
});
<script src="https://unpkg.com/vue/dist/vue.js"></script>
<div id="app">
<span class='prefix'>+{{ prefix }}</span>
<input type='tel' #input="handleInput" :value="withoutPrefix">
<p>Phone: {{ phone }}</p>
</div>
It does not exactly work cause I'm being a bit confused by your example, but I think one way is to use computed getter/setter instead.
data() {
return {
hiddenInputValue: ''
}
},
computed: {
inputValue: {
get() {
return this.hiddenInputValue;
},
set(val) {
// do something with the input value...
this.hiddenInputValue = // assign a modified version of the input value...
}
}
}
You should be able to do something with that, but check my comment. It's probably a better solution.

Vue js input mask

I want to have an input mask on a specific input where it parses the user input into a human readable US phone number.
For example
User enter: 1231231234
User sees: (123)-123-1234
What I have done so far is, i made a watch method like the follow
switch (this.form.values.primary_phone.length) {
case 3:
return this.form.values.primary_phone = this.form.values.primary_phone.replace(/^([0-9]{3})$/, '($1)');
case 6:
return this.form.values.primary_phone = this.form.values.primary_phone.replace(/^([0-9]{3})([0-9]{3})$/, '($1)-$2');
case 10:
return this.form.values.primary_phone = this.form.values.primary_phone.replace(/^([0-9]{3})([0-9]{3})([0-9]{4})$/, '($1)-$2-$3');
}
Now this updates the value only when I focus out of from input. Is there a way I can do it to update while the input is still at focus?
I would recommend you to do a directive wrapping the jquery plugin input mask.
There is an example:
JavaScript
Vue.directive('input-mask', {
params: ['mask'],
bind: function() {
$(this.el).inputmask({
mask: this.params.mask
});
},
});
var vm = new Vue({
el: 'body',
data: {
value: '',
}
});
HTML
<!-- Import Styles/Scripts from the plugin and do not forget the jQuery library -->
<link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/jasny-bootstrap/3.1.3/css/jasny-bootstrap.min.css">
<script src="//cdnjs.cloudflare.com/ajax/libs/jasny-bootstrap/3.1.3/js/jasny-bootstrap.min.js"></script>
<p>Selected: {{value}}</p>
<input v-model="value" v-input-mask mask="(999) 999-9999">
If you need there is a JSBin to show you how it works.
For that you must define a custom filter on your input. Something like this
Vue.filter('mask', function (value) {
if (value.length <= 3){
var re = new RegExp("^([0-9]{"+value.length+"})$");
return value = value.replace(re, '($1)');
}
if (value.length > 3 && value.length <= 6){
var re = new RegExp("^([0-9]{3})([0-9]{"+ (value.length - 3)+"})$");
return value = value.replace(re, '($1)-$2');
}
if (value.length > 6 && value.length <= 10){
var re = new RegExp("^([0-9]{3})([0-9]{3})([0-9]{"+(value.length-6)+"})$");
return value = value.replace(re, '($1)-$2-$3');
}
return value;
})
Then apply that to your template. I made a jsfiddle (based on the markdown example from Vue page)
Notice that you still have to handle values of length greater than 10, and I also changed your function to use if statements instead of switch-case
I use the text-mask plugin which give the same great functionality as the JQuery one without the Jquery bloat.
Github here: https://github.com/text-mask/text-mask
Vue instructions here: https://github.com/text-mask/text-mask/tree/master/vue
const MaskedInput = window.vueTextMask.default
new Vue({
el: '#app',
components: { MaskedInput },
data: {
phone: '',
mask: ['(', /\d/, /\d/,/\d/, ')', '-', /\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/]
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-text-mask#6.1.2/dist/vueTextMask.min.js"></script>
<div id="app">
phone:
<masked-input v-model="phone" :mask="mask" placeholder="(___)-___-____"></masked-input>
</div>