Currently i try to use cleavejs to formatting thousand separator my input number, it's show strange behavior when i input 1000.123 it show 1,000.12 which is correct format, but my v-model value is 1000.123 not 1000.12. other people suggesting using v-model.lazy but it only updated when i leave my focus from input text.
Is there any other way to solve this issue without using v-model.lazy ?
This is my current component
<script setup lang="ts">
import { ref, watch } from 'vue'
const props = withDefaults(defineProps<Props>(), {
type: 'text',
required: false,
readonly: false,
disabled: false
})
const inputValue = ref(props.modelValue)
const emit = defineEmits<{
(e: 'update:modelValue', value: string | number): void
}>()
watch(
() => props.modelValue,
() => {
inputValue.value = numeric.format(props.modelValue)
},
{
immediate: true
}
)
watch(
inputValue,
() => {
emit('update:modelValue', parseFloat(inputValue.value.toString().replace(/(\d+),(?=\d+(\D|$))/g, '$1')))
},
{
immediate: true
}
)
</script>
<template>
<input
class="form-input"
v-model.lazy="inputValue"
v-cleave="{ numeral: true, numeralThousandsGroupStyle: 'thousand' }"
:placeholder="props.placeholder"
:required="props.required"
:readonly="props.readonly"
:disabled="props.disabled"
/>
</template>
I expect v-model return the same value as cleavejs did without using .lazy
First, you don't need use watch
at all, and we won't emit on this setter because we wait Cleavejs event
const inputValue = computed({
set: (text: string) => {},
get: () => new Intl.NumberFormat('en-US').format(props.modelValue)
})
Second, emit raw value data from Cleavejs onValueChanged event
const emit = defineEmits<{
(e: 'update:modelValue', value: number): void
}>()
const onValueChanged = (e: any) => {
emit('update:modelValue', Number(e.target.rawValue))
}
Last, Update your input directive
v-cleave="{ numeral: true, numeralThousandsGroupStyle: 'thousand', onValueChanged: onValueChanged }"
Full Component example
<script setup lang="ts">
import { computed } from 'vue'
export interface Props {
modelValue: number
}
const props = withDefaults(defineProps<Props>(), {})
const inputValue = computed({
set: (text: string) => {},
get: () => new Intl.NumberFormat('en-US').format(props.modelValue)
})
const emit = defineEmits<{
(e: 'update:modelValue', value: number): void
}>()
const onValueChanged = (e: any) => {
emit('update:modelValue', Number(e.target.rawValue))
}
</script>
<template>
<input
v-cleave="{ numeral: true, numeralThousandsGroupStyle: 'thousand', onValueChanged: onValueChanged }"
v-model="inputValue"
/>
</template>