Search code examples
javascriptvue.jsnumber-formatting

Price input formatter


I'm trying to write the code for price input. The task should be simple, but something doesn't work.. I have a Vue project and I need user to enter the price in input field, where the price should be filling form the last char. Example: start value "00.00"; when user enter "1" then value became "00.01", when user add "4" then value became "00.14", when add 2 then "01.42".

The code is kind of works, but just inputted number staying in input field, even if I add event.target.value = "";

new Vue({
  el: '#app',
  data: {
    price: '00.00'
  },
  methods: {
    handleKeyDown(event) {
      const key = event.key;
      const validKeys = ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'];

      if (!validKeys.includes(key)) {
        event.preventDefault();
        return;
      }

      const newPrice = this.price.replace('.', '') + key;
      const parsedPrice = parseFloat(newPrice);

      if (isNaN(parsedPrice) || parsedPrice > 9999) {
        event.preventDefault();
        return;
      }

      const priceWithDecimal = (parsedPrice / 100).toFixed(2);
      this.price = "0" + priceWithDecimal;
      //   event.target.value = "";
      console.log(this.price);
    }
  }
});
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>

<div id="app">
  <input type="text" v-model="price" @keydown="handleKeyDown">
</div>


Solution

  • You can watch the price value for changes instead.

    const
      parseValue  = (v) => parseInt(v.trim().replace(/\./g, ''), 10),
      formatValue = (v) => (v / 100).toFixed(2).replace(/^(\d)(?=\.)/, '0$1');
    
    new Vue({
      el: '#app',
      data: {
        price: '00.00'
      },
      watch: {
        price(newValue, oldValue) {
          const parsed = parseValue(newValue);
          this.price = !isNaN(parsed) ? formatValue(parsed) : oldValue;
        }
      }
    });
    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/vue.js"></script>
    
    <div id="app">
      <input type="number" v-model="price" step="0.01">
    </div>