What is the best approach to transform a lengthy collection of 'watch' statements into a functioning solution using VueJS?

I am new to vueJS and need some help with optimizing my code. I have a long list of watch functions that are all essentially the same, but I'm not sure how to convert them into a more efficient and functional approach.

These watch functions are all related to adding commas in input tags using v-model, and while they work well, the redundancy makes the code look cumbersome. Each function is identical except for its name.

new Vue({
  data: {
    tmp_price1: '',
    tmp_price2: '',
    tmp_price3: '',
    tmp_a_price: '',
    tmp_b_price: '',
  },

  watch: {
   tmp_price1: function(newValue) {
     if (newValue != '') {
       const result = newValue.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
       Vue.nextTick(() => this.tmp_price1 = result);
     }
   },
   tmp_price2: function(newValue) {
     if (newValue != '') {
       const result = newValue.replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
       Vue.nextTick(() => this.tmp_price2 = result);
     }
   },

  ....(repeat)

  },

I would appreciate any suggestions on how to streamline these repetitive watch functions in a more efficient manner.

Answer №1

One way to approach this is by creating a component specifically for handling the comma formatting feature. This component would include a computed property that generates the formatted value, which can then be used by the parent component for updating purposes.

new Vue({
  el: '#app',
  data: {
    tmp_price1: '',
    tmp_price2: '',
    tmp_price3: '',
    tmp_a_price: '',
    tmp_b_price: '',
  },
  components: {
    commafiedInput: {
      props: ['value'],
      template: '<input v-model="commaValue">',
      computed: {
        commaValue: {
          get() {
            return this.value;
          },
          set(newValue) {
            this.$emit('input', this.addCommas(newValue));
          }
        }
      },
      methods: {
        addCommas(v) {
          return v.replace(/\D/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, ",");
        }
      }
    }
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div> {{tmp_price1}}
    <commafied-input v-model="tmp_price1"></commafied-input>
  </div>
  <commafied-input v-model="tmp_price2"></commafied-input>
  <commafied-input v-model="tmp_price3"></commafied-input>
  <commafied-input v-model="tmp_a_price"></commafied-input>
  <commafied-input v-model="tmp_b_price"></commafied-input>
</div>

Answer №2

One way to display the formatted version of a value is by using a simple filter:

new Vue({
  el: '#app',
  data: {
    tmp_price1: '123123',
    tmp_price2: '',
    tmp_price3: ''
  },
  filters: {
    myFilter(v) {
      return v.replace(/\D/g, '').replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }   
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div><input v-model="tmp_price1">{{tmp_price1 | myFilter}}</div>
  <div><input v-model="tmp_price2">{{tmp_price2 | myFilter}}</div>
  <div><input v-model="tmp_price3">{{tmp_price3 | myFilter}}</div>
  
</div>

However, simply applying the filter to the v-model attribute is not sufficient for input fields. A sub-component approach, like the one suggested in Roy J's answer on Stack Overflow, may be the best solution for better reusability. Alternatively, for a quick-and-dirty fix, you can add a change handler as shown below:

new Vue({
  el: '#app',
  data: {
    tmp_price1: '123123',
    tmp_price2: '',
    tmp_price3: ''
  },
  methods: {
    myFormatter(fieldname) {
      /* replace the user's input with the formatted value.
      
          There's probably some clever way to read the v-model 
          name from the input field instead of passing it to the 
          method as a string, but I'm not going to mess around 
          with that for what is after all a quick-and-dirty technique */
      this[fieldname] = this[fieldname].replace(/\D/g, "").replace(/\B(?=(\d{3})+(?!\d))/g, ",");
    }
  },
  mounted() {
    // if the initial values aren't always empty, you'll need to run the
    // formatter function on component load as well as on user input:
    ['tmp_price1', 'tmp_price2', 'tmp_price3'].forEach(f => {
      this.myFormatter(f);
    });
  }
});
<script src="https://unpkg.com/vue@latest/dist/vue.js"></script>
<div id="app">
  <div><input v-model="tmp_price1" @input="myFormatter('tmp_price1')">{{tmp_price1}}</div>
  <div><input v-model="tmp_price2" @input="myFormatter('tmp_price2')">{{tmp_price2}}</div>
  <div><input v-model="tmp_price3" @input="myFormatter('tmp_price3')">{{tmp_price3}}</div>
</div>

(Another approach, highlighted in this answer to a similar query, uses a Vue directive to bind the input events instead of adding @input handlers.)

It's important to note that in the "filter" version, the original user input remains in the v-model values while the filtered value is displayed. On the other hand, in the second example, the formatting directly applies to the v-modeled values themselves, ensuring that any subsequent usage includes the formatted version. Depending on the situation, either or both techniques can prove helpful. In fact, combining them – removing non-digits in the v-model and then adding commas via a display-only filter, for instance – can also enhance functionality.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Utilizing AngularJS to display a table with Rowspan functionality and the ability to filter elements

I am trying to develop an HTML table that utilizes rowspan with ng-repeat to group data effectively. The overall layout is functioning as expected, but I encountered a problem when attempting to apply filters to the table. Specifically, when I filter the ...

Unable to display the string following a space in the value attribute of an hbs file

<input type="text" class="form-control" id="exampleInputEmail2" name="productName" value={{product.productName}} > When I input 'Smart Phones' into product.produc ...

Add a npm module without type definitions

I am currently utilizing Typescript version 2.1 and facing an issue with installing an npm package called 'reactable' that lacks typings. When attempting to import the package using import * as Reactable from 'reactable', Typescript di ...

Transform a JQuery function using the each method into vanilla JavaScript

Seeking assistance. I have developed a multilingual static site using JQuery and JSON, but now I want to switch to simple JS. Most of the code is ready, except for the portion commented out in the JS (which works fine with JQuery). var language, transla ...

How can I update a dropdown menu depending on the selection made in another dropdown using Angular

I am trying to dynamically change the options in one dropdown based on the selection made in another dropdown. ts.file Countries: Array<any> = [ { name: '1st of the month', states: [ {name: '16th of the month&apos ...

Tips for deactivating all JavaScript events on a webpage that has been loaded within an iframe

My website is equipped with various JS click/mouseover/mouseout/scroll events and incorporates several JS libraries to operate features such as carousels, bootstrap modal pop-ups, and more. I am looking to halt all events on a specific element. Although I ...

Executing numerous HTTP requests in a single Node.js HTTP request

I am attempting to make a single URL call that will fetch multiple URLs and store their JSON responses in an array, which will then be sent as the response to the end user. Here is what my code looks like: var express = require('express'); var ...

Tricks for preventing axios from caching in GET requests

I am utilizing axios in my React-Native application Firstly, I set up the headers function setupHeaders() { // After testing all three lines below, none of them worked axios.defaults.headers.common["Pragma"] = "no-cache"; axios.defaults.heade ...

Having trouble with $.post request to a different domain in a node.js/express app running on port 8081

Whenever I try to use $.post, I keep getting the error message POST https://thewebsite.com 400 (Bad Request). Here is the code snippet that's causing the issue: $.post("https://website.com/blabla", { domain: "infoinfo.com", room: "someInfo", ap ...

Guide to setting up value observation in React Context for optimal functionality

Imagine a scenario where there is a Parent Component that provides a Context containing a Store Object. This Store holds a value and a function to update this value. class Store { // value // function updateValue() {} } const Parent = () => { const ...

TypeError: The file extension ".json" is not recognized

Hello, Developers! command: => cross-env NODE_ENV=production node server.mjs Error node:internal/errors:464 ErrorCaptureStackTrace(err); ^ TypeError [ERR_UNKNOWN_FILE_EXTENSION]: Unknown file extension ".json" for /home/windows/Docume ...

Is there a way to retrieve the data selected in my modal window when a button is clicked, depending on the v-for value?

As someone who is new to Vue and utilizing Bootstrap modals to showcase product information, I have grid containers that contain a product image, description, and two buttons. One of the buttons, labeled More details >>, is intended to trigger a moda ...

Reactjs: Could someone provide a more detailed explanation of this statement?

After reading this line in the documentation here, I came across an interesting code snippet. this.setState({ chats: [...this.state.chats, data], test: '' }); It seems like we are adding to the 'chats' array in the state, but I&ap ...

Tool for obfuscating client-side files using node.js

I'm in search of a tool similar to the one found at but in the form of a node.js module, allowing for obfuscation of client-side js files prior to transmission. The tool mentioned above performs various tasks, with its most crucial function being th ...

Is it possible to implement localStorage for auto-filling multiple forms simultaneously on a single webpage

I have been exploring a code snippet by Ke Yang that uses localStorage to synchronize text in form fields across different fields. I am interested in implementing something similar. On a page where I have a library of downloadable items, there are approxi ...

Leverage the key-value pairs in JSON to automatically suggest types within the function parameters

If we have data structured like this: { "key1": "hardcoded string", "key2": "another hardcoded string", } Imagine a function with 2 parameters where the first parameter should refer to key1 and the second to i ...

Using PHP and JavaScript to enhance functionality around a hyperlink

I am trying to incorporate a small piece of Javascript on my website to ensure user confirmation. While I have successfully used the 'onclick' function with buttons, I am facing difficulty implementing it on a link. Here is the link in question: ...

Tips on organizing and designing buttons within a canvas

let canvas = document.getElementById("canvas"); let context = canvas.getContext("2d"); // for canvas size var window_width = window.innerWidth; var window_height = window.innerHeight; canvas.style.background="yellow" canvas.wid ...

How to implement form modal binding using Laravel and Vue.js

There are two models named Tour.php public function Itinerary() { return $this->hasMany('App\Itinerary', 'tour_id'); } and Itinerary.php public function tour() { return $this->belongsTo('App\Tour', ...

There was an issue retrieving the value from the $.ajax() error function, as it returned [

After successfully receiving data from the input field and sending it to the database, everything seems to be working fine. However, when attempting to retrieve the data after sending it to the database, an error is encountered: [object HTMLInputElement]. ...