Vue.Js 2 Input formatting number - input

I have been struggling to get a number input to format numbers using vuejs2.
Migrating some view logic from asp.net core 2 to vue and I was using this:
<input asp-for="Model.LoanAmount" value="#(Model.LoanAmount > 0 ? Model.LoanAmount.ToString("N2") : String.Empty)" >
but that required me to reload that view onchange of the input.
I need a way to format number inputs with US format and 2 decimal places, (1,000,000.21) but to display nothing when the model value is zero or empty.
vue-numeric does ALMOST everything, but fails for me when I try to use a placeholder.
<vue-numeric v-model="vm.loanAmount" seperator="," placeholder=" " :precision="2" ></vue-numeric>
I tried using a space for placeholder because it crashes when I use an empty string.
This example displays 0.00 if zero or empty is inputted. I tried playing with the output-type and empty-value props.
I'm not wedded to vue-numeric but it is handy because I don't know of a more convenient solution.

You can achieve the formatting by simply using a computed property with separate getter and setter without the need for other dependencies.
computed: {
formattedValue: {
get: function() {
return this.value;
},
set: function(newValue) {
if (newValue.length > 2) {
newValue = newValue.replace(".", "");
this.value =
newValue.substr(0, newValue.length - 2) +
"." +
newValue.substr(newValue.length - 2);
} else {
this.value = newValue;
}
}
}
}
https://codesandbox.io/s/p7j447k7wq
I only added the decimal separator as an example, you'll have to add the , thousand separator in the setter for your full functionality.

Related

Vuejs : How to not a boolean value in V-model?

I am getting value of options.customerdata.showbutton as true from an API, so now the switch is in on condition.
I want the switch to be in off, hence v-model="false" should be given. But
tried giving
v-model="!(options.customerdata.showbutton)"
does not work and shows error. How to achieve this?
<b-form-checkbox v-model="options.customerdata.showbutton" name="logo-display" switch >
</b-form-checkbox>
Model can't be expression (it must be reference to data/property)
Easiest way is define data and set it with negated value. But be aware that in this case your model is not change when customerdata is changed after component initialization.
data: {
return {
show: !this.options.customerdata.showbutton
}
}
If you need to store value back to options (or bound value to customerdata), you can use also computed property with setter/getter
computed {
show: {
get () {
!this.options.customerdata.showbutton
}
set (value) {
this.options.customerdata.showbutton = !value
}
}
}
For both case your bind it with
v-model="show"

Input field not reacting to data changes after being written to by a user

While creating a Vue.js application I have become stuck at a weird problem. I want to be able to manipulate an input field (think increment and decrement buttons and erasing a zero value on focus, so the user doesn't have to) and up until a user writes to the input field, everything is fine. After that, however, further changes in the data are no longer represented in the input field.
As I was sure I could not be the only one with this particular problem, I searched extensively, but had no luck. What baffles me the most is that everything works until the field is written to, since I can not really imagine why this would remove the data binding.
The following code should show the same behavior. It is an input field component, which is initialized with a zero value. On focus the zero gets removed. This works, until a user manually writes to the field after which zero values will no longer be removed, even though the focus method fires, the if-condition is met and the data in the amount-variable is changed.
Vue.component('item', {
data: function () {
return {
amount: 0
}
},
render: function (createElement) {
var self = this;
return createElement('input', {
attrs: {
//bind data to field
value: self.amount,
type: 'number'
},
on: {
//update data on input
input: function (event) {
self.amount = event.target.value;
},
//remove a zero value on focus for user convenience
focus: function (event) {
if (self.amount == 0 || self.amount == "0") {
self.amount = '';
}
}
}
})
}
})
I think you need to use domProps instead of attrs to make it reactive. But I would suggest you use vue's template syntax or if you insist on using the render function I would also suggest you to use JSX.

How to use currency on type=Number when value is using computed data?

Okay, so I have an input field with below code and wanting use decimals to look like 10,000 for 100000.
input#payment.form-control(type='number'
v-model='payment')
Payment for v-model is coming from computed data using mixin and updates new value using methods.
computed:{
get () { return this.NameOfMixin.payment },
set (value) {this.updateStore('payment', value)}
},
methods: {
updateStore(field, value) {
...
}
}
All the code above are working fine except now I want to display decimals and use a plain number for updating the store.
I have tried using creating methods to convert the value to decimals and v-money but nothing worked as I wished.

Vuetify Autocomplete minimum character before filtering

Is there a property or a method that will prevent Vuetify Autocomplete to filter items to display until a certain condition is met, such as 3 character typed? I have a basic solution but I really hope that there is another solution. I don't want anything to show until the end user types a minimum of three characters. I have a solutions such as:
watch: {
search (val) {
if(val.length > 2){
this.minimumCharacter = 'show'
}else{
this.minimumCharacter = 'null'
}
And in my HTML:
<template
v-if="minimumCharacter === 'show'"
slot="item"
slot-scope="{ item, tile }"
>
Surely the Autocomplete has a property somewhere that will handle this. When you have thousands and thousands of records you don't really want everything to show as soon as you type one character. But I've search https://vuetifyjs.com/en/components/autocompletes#autocomplete and unless they call it something that I can not relate its not there.
Surely the Autocomplete has a property somewhere that will handle this. When you have thousands and thousands of records you don't really want everything to show as soon as you type one character. But I've search https://vuetifyjs.com/en/components/autocompletes#autocomplete and unless they call it something that I can not relate its not there.
I cannot find such property, but for me works fine this variant:
watch: {
search (val) {
if(val.length > 2){
//search code
}
P.S. Filter starts working after search, so it doesn't solve current task to prevent search.
You can use filter prop to implement your own filter function that always returns false if text length is less then 3:
(item, queryText, itemText) => {
const hasValue = val => val != null ? val : ''
const text = hasValue(itemText)
const query = hasValue(queryText)
if(queryText < 3) return false;
return text.toString()
.toLowerCase()
.indexOf(query.toString().toLowerCase()) > -1
}

What's the proper way to implement formatting on v-model in Vue.js 2.0

For a simple example: textbox to input currency data.
The requirement is to display user input in "$1,234,567" format and remove decimal point.
I have tried vue directive. directive's update method is not called when UI is refreshed due to other controls. so value in textbox reverts to the one without any formatting.
I also tried v-on:change event handler. But I don't know how to call a global function in event handler. It is not a good practice to create a currency convert method in every Vue object.
So what is the standard way of formatting in Vue 2.0 now?
Regards
Please check this working jsFiddle example: https://jsfiddle.net/mani04/bgzhw68m/
In this example, the formatted currency input is a component in itself, that uses v-model just like any other form element in Vue.js. You can initialize this component as follows:
<my-currency-input v-model="price"></my-currency-input>
my-currency-input is a self-contained component that formats the currency value when the input box is inactive. When user puts cursor inside, the formatting is removed so that user can modify the value comfortably.
Here is how it works:
The my-currency-input component has a computed value - displayValue, which has get and set methods defined. In the get method, if input box is not active, it returns formatted currency value.
When user types into the input box, the set method of displayValue computed property emits the value using $emit, thus notifying parent component about this change.
Reference for using v-model on custom components: https://v2.vuejs.org/v2/guide/components.html#Form-Input-Components-using-Custom-Events
Here is a working example: https://jsfiddle.net/mani04/w6oo9b6j/
It works by modifying the input string (your currency value) during the focus-out and focus-in events, as follows:
<input type="text" v-model="formattedCurrencyValue" #blur="focusOut" #focus="focusIn"/>
When you put the cursor inside the input box, it takes this.currencyValue and converts it to plain format, so that user can modify it.
After the user types the value and clicks elsewhere (focus out), this.currencyValue is recalculated after ignoring non-numeric characters, and the display text is formatted as required.
The currency formatter (reg exp) is a copy-paste from here: How can I format numbers as money in JavaScript?
If you do not want the decimal point as you mentioned in question, you can do this.currencyValue.toFixed(0) in the focusOut method.
I implemented a component. According to Mani's answer, it should use $emit.
Vue.component('currency', {
template: '<input type="text"' +
' class="form-control"' +
' :placeholder="placeholder""' +
' :title="title"' +
' v-model="formatted" />',
props: ['placeholder', 'title', 'value'],
computed: {
formatted: {
get: function () {
var value = this.value;
var formatted = currencyFilter(value, "", 0);
return formatted;
},
set: function (newValue) {
var cleanValue = newValue.replace(",", "");
var intValue = parseInt(cleanValue, 10);
this.value = 0;
this.value = intValue;
}
}
}
}
);
Using Vue custom directives + .toLocaleString() is also a very good option.
Vue.directive("currency", {
bind(el, binding, vnode) {
el.value = binding.value && Number(binding.value).toLocaleString('en-US', {style: 'currency', currency: !binding.arg ? 'USD' : binding.arg });
el.onblur = function(e) {
e.target.value = Number(e.target.value).toLocaleString('en-US', {style: 'currency', currency: !binding.arg ? 'USD' : binding.arg});
};
el.onfocus = function(e) {
e.target.value =
e.target.value && Number(e.target.value.replace(/[^\d.]/g, ""));
};
el.oninput = function(e) {
vnode.context.$data[binding.expression] = e.target.value;
};
}
});
Here is the example link: https://codepen.io/Mahmoud-Zakaria/pen/YzPvNmO