Reputation: 1607
I have a form, on which I am trying to use Vue's "currency" filter on certain inputs that are then validated using Vue Validator (https://github.com/vuejs/vue-validator).
HTML
<validator name="foo">
<input id="example" type="tel" v-model="baz | currency" v-validate:bar="['required']" />...
<span> equals {{ baz }}</span>...
</validator>
JavaScript
Vue.config.warnExpressionErrors = false;
var vm = new Vue({
el: '#demo',
data: {
baz: ''
}
});
The filtered and validated fields update with every keystroke — such that they are cleared/reset each time. The effect is that attempting to key in a number, such as 1234, will result in the <input>
showing "$3.004" or "$4.00" (though you may see: "$1.00" "$1.002" "$2.00" "$2.003" or "$3.00" as you type).
I'm thinking there's a conflict between the filter and the component for which gets the final say over the value(?)
There's a very good possibility that I'm not implementing this correctly. I distilled the issue down to the salient components int he following JSFiddle…
http://jsfiddle.net/itopizarro/b9a2oyL4/
Upvotes: 3
Views: 1453
Reputation: 12711
I think the main problem has to do with the currency
filter. Every time there's a key
event in your input, the following things occur:
When you type 1-2-3, it goes like this:
1 =>
2 =>
3 =>
Part of the problem is that the built-in currency
filter is a one-way filter - it formats the model for display but doesn't do anything when data is written back. You could try writing your own two-way currency filter. Here's a sample:
Vue.filter('currencyInput', {
// model -> view
read: function(value) {
// use the built-in currency filter for display
var currencyFilter = Vue.filter('currency');
return currencyFilter(value);
},
// view -> model
write: function(value, oldValue) {
var number = +value.replace(/[^\d.]/g, '')
return isNaN(number) ? 0 : parseFloat(number.toFixed(2))
}
})
This ensures that the model is displayed as currency but written/stored as a number. This is still not perfect though because every time you keyup, the data gets formatted and the cursor moves to the end.
You could use the debounce
or lazy
attributes on the input so the update doesn't occur until the user has paused or moved on from the field.
<input id="example" type="tel" v-model="baz | currencyInput" debounce="500" v-validate:baz="['required']" />
But then you don't get the immediate formatting as the user types.
I guess it depends on your requirements. Hopefully this gives you some ideas.
Upvotes: 2