Skip to content

Instantly share code, notes, and snippets.

@Christilut
Created June 7, 2018 18:14
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 4 You must be signed in to fork a gist
  • Save Christilut/1143d453ea070f7e8fa345f7ada1b999 to your computer and use it in GitHub Desktop.
Save Christilut/1143d453ea070f7e8fa345f7ada1b999 to your computer and use it in GitHub Desktop.
Vuetify Currency Field
<template lang="pug">
v-text-field(
ref='field',
:prefix='prefix',
v-model='model',
@focus='onFocus',
@keyup='onKeyUp',
:error-messages='errorMessages',
v-bind='$attrs',
@change='onChange'
@blur='onBlur'
)
</template>
<script>
function tryParseFloat (str, defaultValue) {
var retValue = defaultValue
if (str !== null) {
if (str.length > 0) {
if (!isNaN(str)) {
retValue = parseFloat(str)
}
}
}
return retValue
}
export default {
props: {
value: null,
'error-messages': null,
allowNegative: {
type: Boolean,
default: false
},
prefix: {
type: String,
default: '$ '
},
thousandsSeparator: {
type: String,
default: ','
},
decimalSeparator: {
type: String,
default: '.'
},
languageCode: {
type: String,
default: 'en-US'
}
},
data () {
return {
numberValue: this.value,
model: this.value,
isMasked: true,
thousandsSeparatorRegex: new RegExp(`\\${this.thousandsSeparator}`, 'g'),
decimalSeparatorRegex: new RegExp(`\\${this.decimalSeparator}`, 'g')
}
},
methods: {
onFocus () {
this.isMasked = false
this.updateModel()
},
onBlur () {
if (this.$listeners.blur) this.$listeners.blur()
this.isMasked = true
this.format()
},
onKeyUp () {
this.updateNumberValue()
},
onChange () {
if (this.$listeners.change) this.$listeners.change()
},
updateNumberValue () {
let v = this.model
let parsed
v = v.replace(this.thousandsSeparatorRegex, '')
if (this.decimalSeparator !== '.') v = v.replace(this.decimalSeparatorRegex, this.thousandsSeparator)
const result = tryParseFloat(v)
if (!result) parsed = 0
else parsed = result
if (!this.allowNegative && result < 0) parsed = 0
this.numberValue = Math.round(parsed * 100) / 100
},
updateModel () {
if (this.numberValue === null) return
let v = this.numberValue.toString()
v = v.replace(this.thousandsSeparatorRegex, this.decimalSeparator)
this.model = v
},
format () {
if (this.numberValue === null) return
let v = this.numberValue
v = v.toLocaleString(this.languageCode)
if (v.length !== 1 && v.slice(v.indexOf(this.decimalSeparator) + 1).length === 1) v += '0'
this.model = v
}
},
watch: {
numberValue (v) {
this.$emit('input', v)
},
value (v) {
this.numberValue = v
if (!this.$refs.field.isFocused) {
this.format()
}
}
},
created () {
this.format()
}
}
</script>
<style lang="scss" scoped>
</style>
@Christilut
Copy link
Author

Usage just like VTextField:

  currency-field(
    label='Price',
    v-model.number='price',
    :error-messages='priceValidationErrors',
    @change='$v.price.$touch',
    @blur='$v.price.$touch',
    )

@scottpage
Copy link

Saved my day, thanks!

@bajki
Copy link

bajki commented Aug 29, 2018

How to format to 10.000,00 ?
Because now is 10.000

@MarouaneSH
Copy link

MarouaneSH commented Sep 9, 2018

Here is the code if anyone want to format currency onKeyup
`
<v-text-field
ref='field'
:prefix="prefix"
v-model="model"
@Focus="onFocus"
@keyup="onKeyUp"
:error-messages="errorMessages"
v-bind="$attrs"
@change="onChange"
@blur="onBlur"

<script> function tryParseFloat (str, defaultValue) { var retValue = defaultValue if (str !== null) { if (str.length > 0) { if (!isNaN(str)) { retValue = parseFloat(str) } } } return retValue } export default { props: { value: null, 'error-messages': null, allowNegative: { type: Boolean, default: false }, maxNumber : { type : Number, default: 5, }, prefix: { type: String, default: '$ ' }, thousandsSeparator: { type: String, default: ',' }, decimalSeparator: { type: String, default: '.' }, languageCode: { type: String, default: 'en-US' } }, data () { return { numberValue: this.value, model: this.value, isMasked: true, thousandsSeparatorRegex: new RegExp(`\\${this.thousandsSeparator}`, 'g'), decimalSeparatorRegex: new RegExp(`\\${this.decimalSeparator}`, 'g') } }, methods: { maskInput(){ return "#".repeat(this.maxNumber); }, onFocus () { //x this.updateModel() }, onBlur () { if (this.$listeners.blur) this.$listeners.blur() this.isMasked = true this.format() }, onKeyUp (event) { if(isNaN(String.fromCharCode(event.which))) { event.preventDefault(); //stop character from entering input } this.updateNumberValue(); this.format(); }, onChange () { if (this.$listeners.change) this.$listeners.change() }, updateNumberValue () { let v = this.model let parsed v = v.replace(this.thousandsSeparatorRegex, '') if (this.decimalSeparator !== '.') v = v.replace(this.decimalSeparatorRegex, this.thousandsSeparator) const result = tryParseFloat(v) if (!result) parsed = 0 else parsed = result if (!this.allowNegative && result < 0) parsed = 0 this.numberValue = Math.round(parsed * 100) / 100 }, updateModel () { if (this.numberValue === null) return let v = this.numberValue.toString() v = v.replace(this.thousandsSeparatorRegex, this.decimalSeparator) this.model = v }, format () { if (this.numberValue === null) return let v = this.numberValue v = v.toLocaleString(this.languageCode) if (v.length !== 1 && v.slice(v.indexOf(this.decimalSeparator) + 1).length === 1) v += '0' this.model = v } }, watch: { numberValue (v) { this.$emit('input', v) }, value (v) { this.numberValue = v if (!this.$refs.field.isFocused) { this.format() } } }, created () { this.format() } } </script> <style lang="scss" scoped> </style>`

@abishekrsrikaanth
Copy link

Is there a way to restrict alphabets on change/input?

@thiagosantos
Copy link

Hello @Christilut!
Thank you for this gist.

I made a mod to support precision numbers greater than 2.

props:{
//....
   precision:{
      type: Number,
      default: 2
    }
}

in data add nprecision

data() {
    return {
	//...
	    nprecision: this.precision,
	//...
    }
}

at the methods add a new method roundNumber, in "updateNumberValue" change Math.round call to "this.roundNumber(parsed, this.nprecision)" and alter "format" methods add a new parameter to v.toLocaleToString

methods:{
roundNumber(num, scale) {
      //https://stackoverflow.com/a/12830454/4537233
      if(!("" + num).includes("e")) {
        return +(Math.round(num + "e+" + scale)  + "e-" + scale);
      } else {
        var arr = ("" + num).split("e");
        var sig = ""
        if(+arr[1] + scale > 0) {
          sig = "+";
        }
        return +(Math.round(+arr[0] + "e" + sig + (+arr[1] + scale)) + "e-" + scale);
      }
    },
    updateNumberValue () {
      let v = this.model
      let parsed
      v = v.replace(this.thousandsSeparatorRegex, '')
      if (this.decimalSeparator !== '.') v = v.replace(this.decimalSeparatorRegex, this.thousandsSeparator)
      const result = tryParseFloat(v)
      if (!result) parsed = 0
      else parsed = result
      if (!this.allowNegative && result < 0) parsed = 0
      this.numberValue = this.roundNumber(parsed, this.nprecision); //Math.round(parsed * 100) / 100
    }
//....
format () {
      if (this.numberValue === null) return
      let v = this.numberValue
      v = v.toLocaleString(this.languageCode, {maximumFractionDigits:this.nprecision})
      if (v.length !== 1 && v.slice(v.indexOf(this.decimalSeparator) + 1).length === 1) v += '0'
      this.model = v
    }

Best!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment