7

I see this topic, But this is Jquery, how can I change it to Vue.js ? Is v-on supported in Vue.js? Where is my mistake?

<div id="vue">
    <input v-model="amountModel" v-on:keyup="AddCammas()" value="{{price}}">
</div>

<script>
   el: #vue,
   methods:{
      AddCammas : funtion(){
          if(event.which >= 37 && event.which <= 40) return;

          $(this).val(function(index, value) {
             this.message = this.amountModel
                .replace(/\D/g, "")
                .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
           });
      } 
   }   
</script>
Penny Liu
  • 15,447
  • 5
  • 79
  • 98
Morteza Negahi
  • 3,305
  • 8
  • 24
  • 42

6 Answers6

24

You don't need jQuery at all for this. You watch your variable, and in the watch function, compute the reformatted version, then set it back to your variable using nextTick (so it's not mutating before the watch is complete).

new Vue({
  el: '#vue',
  data: {
    price: 0
  },
  watch: {
    price: function(newValue) {
      const result = newValue.replace(/\D/g, "")
        .replace(/\B(?=(\d{3})+(?!\d))/g, ",");
      Vue.nextTick(() => this.price = result);
    }
  }
});
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/1.0.28/vue.min.js"></script>
<div id="vue">
  <input type="text" v-model="price" />{{price}}
</div>
Roy J
  • 42,522
  • 10
  • 78
  • 102
  • 2
    Is there any way if this will work if `input type="number"`? –  Apr 23 '18 at 02:11
  • It works with `type="number"`, but the input will be considered invalid. – Roy J Apr 24 '18 at 20:54
  • how would this work on an object? eg: `proposal.price`. – WhiteRau Oct 14 '20 at 21:23
  • You can `watch` members of objects, @WhiteRau – Roy J Oct 19 '20 at 22:30
  • 1
    @RoyJ Should add `.replace(/^0+/g, '')` to get rid of leading zero. – Penny Liu Feb 13 '22 at 13:35
  • @RoyJ Sorry to ping you again in this thread. I think this implementation having a flaw. For example if I type in a number in the middle, the caret resets to the end of the input. Apart from that, use [`this.$nextTick`](https://v2.vuejs.org/v2/guide/reactivity.html#:~:text=There%20is%20also%20the%20vm.%24nextTick() "nextTick") might be a good practice. – Penny Liu Feb 17 '22 at 14:23
  • 1
    @PennyLiu Those are separate issues from the question asked. To solve the cursor position issue, you'd have to note where your cursor is and then put it back. I think I answered such a question at some point. Alternatively, you could use `v-model.lazy` so that it only gets updated when you're done with input. – Roy J Feb 17 '22 at 19:36
  • 1
    @PennyLiu [Here](https://stackoverflow.com/a/55479433/392102) is the cursor-position answer. Note that the commas in this problem make it trickier. – Roy J Feb 17 '22 at 19:39
4

To people who are looking for doing mask for multiple fields then it's kinda pain to use watch, so may be we can use v-money (docs included). And check the demo here.

Syed
  • 15,657
  • 13
  • 120
  • 154
2

If you are using Vuetify, a new light-weight library called 'vuetify-money' has been published. Super easy to use for money value inputs, it is a text field that will add commas as you type. Here's a demo.

All properties you use on a v-text-field can also be used, so it is easily customizable.

Step 1

npm install vuetify-money --save

Step 2

Create a src/plugins/vuetify-money.js file with the following content:

import Vue from "vue";
import VuetifyMoney from "vuetify-money";
Vue.use(VuetifyMoney);
export default VuetifyMoney;

Step 3

Add file to src/main.js :

import "./plugins/vuetify-money.js";

(main.js is the file where you usually put this)

new Vue({render: h => h(App)
}).$mount('#app');

Step 4 Use it in your code !

<template>
  <div>
    <vuetify-money
      v-model="value"
      v-bind:options="options"
    />
    Parent v-model: {{ value }}
  </div>
</template>
<script>
export default {
  data: () => ({
    value: "1234567.89",
    options: {
      locale: "ja-JP",
      prefix: "$",
      suffix: "",
      length: 10,
      precision: 2
    }
  })
};
</script>

You now have a text field that will add commas as you type while keeping the v-model values perfectly fine. It also prevents any non-number inputs so you hardly need front-end validation checks excluding customized cases.

Jonathan Lee
  • 1,302
  • 1
  • 7
  • 15
1

If you want to use your method, you can make your AddCommas method like this :

AddCommas: function(event) {
  event.target.value = event.target.value.replace(",", ".");
}

There is a little thing to know about event listener in VueJS. You can access the event object in the handler, but for this, you need either to use this syntax v-on:keyup="AddCommas" (no parentheses), or this syntax v-on:keyup="AddCommas($event)" (useful when you have multiple parameters)

Penny Liu
  • 15,447
  • 5
  • 79
  • 98
JosselinTD
  • 611
  • 1
  • 8
  • 17
0

I used Inputmask with vanilla, for vue 2, and it works perfectly. Inputmask

    <script src="../src/assets/js/libs/jquery-inputmask/inputmask.min.js"></script>
  <script src="../src/assets/js/libs/jquery-nputmask/bindings/inputmask.binding.js">

<script>
  $(document).ready(function () {
    var selector = document.getElementById("txtOrderQty");
    var im = new Inputmask({ alias: "currency", digits: 0, allowMinus: false }
    im.mask(selector);
</script>
0

<template>
  <div class="form-group">
    <label :class="{required:$attrs.required}">{{ label }}</label>
    <input v-model="model" class="form-control" :class="{invalid : error}" type="text" pattern="\d+((\.|,)\d+)?"
           v-bind="$attrs">
    <div v-if="error" class="invalid-tooltip">{{ error[0] }}</div>
  </div>
</template>

<script>
export default {
  name: "InputNumber",
  emits: ['update:modelValue'],
  inheritAttrs: false,
  props: {modelValue: '', error: '', label: ''},
  computed: {
    model: {
      get() {
        // return this.modelValue ? this.modelValue.toString().replace(/(\d)(?=(\d\d\d)+(?!\d))/g, "$1,") : this.modelValue
        return this.modelValue ? this.modelValue.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : this.modelValue
      },
      set(value) {
        this.$emit('update:modelValue', Number(value.replaceAll(',','')))
      }
    },
  }
}
</script>