Cleave is not working with vue/vuetify
https://github.com/vuetifyjs/vuetify/issues/6910#issuecomment-479798524
There is really nothing wrong with Cleave or Vuetify. Here is my v-text-field wrapper component which works perfectly with Cleave.
<script>
import Cleave from 'cleave.js';
export default {
props: {
value: {
type: [String, Number],
required: false,
default: '',
},
},
data() {
return {
currentValue: this.value,
};
},
mounted() {
this.cleave = new Cleave(this.$el.querySelector('input'), {
numeral: true,
onValueChanged: this.onValueChanged.bind(this),
});
this.cleave.setRawValue(this.value);
},
methods: {
onValueChanged({ target }) {
this.$nextTick(() => {
this.currentValue = target.value;
this.$emit('input', target.rawValue);
});
},
},
};
</script>
<template>
<v-text-field
v-model="currentValue"
v-bind="$attrs"
:label="$t(domain)"
height="22"
class="caption rbx-text-input"
/>
</template>
I would like to mention two specific lines here.
this.$nextTick(() => { ... } in onValueChanged methodThis is the actual trick to prevent entering non-numeric characters to target input. Also, to be able to show Cleave formatted value properly in a Vuetify textarea, you have to use a $nextTick. Without this formatting will be wrong.
this.cleave.setRawValue(this.value); in the mounted hookThis will set the initial value you got from your server so that Cleave can format it properly. Without this line, if you use custom delimiter and numeralDecimalMark in Cleave options, Cleave won't be able to show correctly formatted value.
For those that are still having issues binding Cleave to this.$refs.input (or whatever) -- I found a surprisingly easy fix that hasn't been documented yet:
v-model.lazy="foo"
The .lazy modifier makes Vue wait for Cleave to validate by binding to change events (instead of input events).
@fatihacet thanks this works for me.. for other people reference :)
but i was looking to make this as directive much easier to apply and maintain i guess ?
`<template>
<v-text-field v-model="currentValue" v-bind="$attrs"></v-text-field>
</template>
<script lang="ts">
import { Component, Vue, Prop, Watch } from 'vue-property-decorator'
import Cleave from 'cleave.js'
import { CleaveOptions } from 'cleave.js/options'
@Component
export default class VTextFormat extends Vue {
@Prop() value!: any
@Prop(Object) readonly option!: CleaveOptions
@Prop(Boolean) readonly raw!: boolean
cleave: Cleave = null
currentValue = this.value
mounted () {
const input = this.$el.querySelector('input')
this.cleave = new Cleave(input, {
...this.option,
onValueChanged: this.onValueChanged.bind(this)
})
this.cleave.setRawValue(this.value)
}
onValueChanged ({ target }) {
this.$nextTick(() => {
let value = this.raw ? target.rawValue : target.value
this.currentValue = target.value
this.$emit('input', value)
})
}
beforeDestroy () {
if (this.cleave) {
this.cleave.destroy()
this.cleave = null
}
}
}
</script>`
Or as directive (Vuetify), it is hackish but works for now.
Vue.directive('cleave', {
bind(el, binding, vnode) {
const input = el.querySelector('input')
// @ts-ignore
input._vCleave = new Cleave(input, binding.value)
},
update: (el) => {
const input = el.querySelector('input')
const event = new Event('input', {bubbles: true});
setTimeout(function () {
input.value = input._vCleave.properties.result
input.dispatchEvent(event)
}, 100);
},
unbind(el) {
const input = el.querySelector('input')
// @ts-ignore
input._vCleave.destroy()
}
})
@harlet That works good but keep in mind that you cannot fill form data with a click anymore. The data shows up for a second and disappears. But for now its a decent workaround to the issue. Just wondering if this is gonna get properly fixed any time?!
Most helpful comment
There is really nothing wrong with Cleave or Vuetify. Here is my
v-text-fieldwrapper component which works perfectly with Cleave.I would like to mention two specific lines here.
this.$nextTick(() => { ... }inonValueChangedmethodThis is the actual trick to prevent entering non-numeric characters to target input. Also, to be able to show Cleave formatted value properly in a Vuetify textarea, you have to use a
$nextTick. Without this formatting will be wrong.this.cleave.setRawValue(this.value);in themountedhookThis will set the initial value you got from your server so that Cleave can format it properly. Without this line, if you use custom
delimiterandnumeralDecimalMarkin Cleave options, Cleave won't be able to show correctly formatted value.