Open kalitk0 opened 2 years ago
Hi, you can use NumberInput.vue as a reference. This is the demo component of the playground.
Might not be that relevant to this specific issue, but for anyone trying to use this with Vue 3. I got it to work with the following composable:
const findInput = (el: HTMLElement | null) =>
(el?.matches('input') ? el : el?.querySelector('input')) as HTMLInputElement
export const useNumericInput = (options: NumberInputOptions, autoEmit?: boolean) => {
let numberInput: NumberInput | null
const inputRef = ref<HTMLInputElement | ComponentPublicInstance | null>(null)
const formattedValue = ref<string | null>(null)
const numberValue = ref<number | null>(null)
const vm = getCurrentInstance()
const emit = vm?.emit || vm?.proxy?.$emit?.bind(vm?.proxy)
const props = (vm?.props || vm?.proxy?.$props) as Record<string, unknown>
const lazyModel = (vm?.attrs.modelModifiers as Record<string, boolean>)?.lazy
const modelValue: ComputedRef<number | null> = computed(() => props?.modelValue as number)
watch(inputRef, (value) => {
if (value) {
const el = findInput((value as ComponentPublicInstance)?.$el ?? value)
if (el) {
numberInput = new NumberInput({
el,
options,
onInput: (value) => {
if (!lazyModel && autoEmit !== false && modelValue.value !== value.number) {
emit?.('update:modelValue', value.number)
}
numberValue.value = value.number
formattedValue.value = value.formatted
},
onChange: (value) => {
emit?.('update:modelValue', value.number)
},
})
numberInput.setValue(modelValue.value)
} else {
console.error('No input element found. Please make sure that the "inputRef" template ref is properly assigned.')
}
} else {
numberInput = null
}
})
return {
inputRef,
numberValue,
formattedValue,
setValue: (value: number | null) => numberInput?.setValue(value),
setOptions: (options: NumberInputOptions) => numberInput?.setOptions(options),
}
}
I am using this composable in the following component:
<script setup lang="ts">
import { NumberInputOptions, NumberFormatStyle, CurrencyDisplay } from 'intl-number-input'
import { PropType } from 'vue'
import { useSettingsStore } from '@/modules/settings/stores/settings'
const { getRegion, getCurrency } = useSettingsStore()
const props = defineProps({
modelValue: { type: Number, default: 0.0 },
options: { type: Object as PropType<NumberInputOptions>, default: null },
})
const { inputRef } = useNumericInput({
locale: getRegion,
currency: getCurrency,
formatStyle: NumberFormatStyle.Currency,
currencyDisplay: CurrencyDisplay.Symbol,
valueRange: {
min: 0,
},
hidePrefixOrSuffixOnFocus: false,
hideGroupingSeparatorOnFocus: false,
hideNegligibleDecimalDigitsOnFocus: false,
autoSign: true,
useGrouping: true,
...props.options,
})
</script>
<template>
<input ref="inputRef" type="text" />
</template>
You can call this component from anywhere, with the option to override any option:
<script setup lang="ts">
const value = ref(undefined)
</script>
<template>
<SharedInputsCurrency v-model.lazy="value" :options="{ currency: 'GBP' }" />
</template>
Only thing I am still struggling with is using this on a Vuetify 3 <v-text-field />
.
@dm4t2 would love to hear your feedback on why you did not create https://github.com/dm4t2/vue-currency-input like this. Since I am missing other numeric inputs (like percent) in that project.
@RiesvGeffen Vue Currency Input is only about inputting currency formatted numbers (like the name says). Intl Number Input on the other hand is a framework-agnostic and generalized implementation.
See also https://github.com/dm4t2/vue-currency-input/discussions/270
Hi, how to use this as component with Vue 2?