Vue Monetary Input Masking

Viewed 100

I'm using Vue2 and I have the following problem:

In my order system, there's an input called value. In here, the client inputs the total value of an order he placed. So, the user inputs 9940 and the input should show 99,40.

Here's my value input:

            <div class="col-md-6">
                <label for="valor">Valor</label>
                <input @keydown="maskValor" class="form-control" type="number" name="valor" id="valor" placeholder="Valor" v-model="newOS.valor" ref="inputValor">
            </div>

As you can see, the problem I'm having is that I CANNOT change the actual newOS.valor (which is the value I'm trying to mask), as they are calculated in cents throught the whole system.

IDEALLY, the input tag would start with a show value of 0,00 (and a newOS.valor of 0), and as the user inputs a number, it gets added to the BACK of the value:

Starts at 0,00
User inputs 4
New value: 0,04
User inputs 5
New value: 0,45
User inputs 1
New value: 4,51
User inputs 000
New value: 4.510,00

So on and so forth, BUT the newOS.valor would STILL be 451000, NOT 4.510,00. I'd be very thankful if someone could point me towards the right direction, as I'm very new at this and am extremely lost at where to begin. I know I could use regex to mask the input, but if I do a replace() on newOS.valor itself, it borks the rest of the system.

Thanks in advance!

1 Answers

What a great question. So, the issue you have is that binding to an input will always bind the input value, to that property. My first thought is that you can use computed values, but you quickly run into the same problem.

But there is a lesser used aspect to the computed property that is the computed getters and setters — https://v2.vuejs.org/v2/guide/computed.html#Computed-Setter

This might be just what you are after.

var v = new Vue({
  el: "#app",
  data() {
    return {
      // This is the value that we use in our app, but not our display:
      val: 0,
    };
  },
  computed: {
    value: {
      // Assuming you are in the same country as toLocalString(), this should work:
      get: function () {
        return (this.val/100).toLocaleString().padStart(4, "0.00")
      },
      // setter
      set: function (newValue) {
        // This is a cheeky regex, that can remove any non-digit character:
        newValue = parseInt(newValue.replace(/\D+/g, ''));
        // Handle edge cases
        if(isNaN(newValue)){
          newValue = 0; 
        }
        this.val = newValue;
      }
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.17/vue.js"></script>

<div id="app">
  <!-- Bind to copmuted property "value" -->
  <input type="text" v-model="value" />
  <code v-text="val"></code>
</div>

I'm sure you could write a much better number parsing expression, but I thought I'd just do the basics so you can see how to transform the input back and forth.

Related