Dynamic Management of Watchers in Vue.js

I'm facing an issue with a component that has a table row containing multiple fields. When I update one field, it triggers changes in another field based on margin or sell price.

However, monitoring all the fields results in a bouncing effect. Adding debounce somewhat mitigates the problem but doesn't fully eliminate it. In an attempt to handle this, I'm using callbacks in watchers to trigger unwatch() but when re-adding the watchers, the callbacks stop working properly.

I have included a functional gist as a code example for reference.

view example gist

Vue.component('pricing', {

  template: '#pricing-row',

  props: ['item'],

  mounted() {
    this.addWatchers()
  },

  methods: {

      resetWatchers() {
        setTimeout(()=> {
            this.addWatchers()
        }, 700)
    },

    addWatchers() {

      this.updateNet = this.$watch(
        function() {
            return this.item.net
        },
        function() {
            // unmount other watchers
            this.updateMargin()
            this.updateSell()
            // calculate sell price and update
            this.setSellPrice()
            // re-add watchers
            this.resetWatchers()
        }
      ),

      this.updateMargin = this.$watch(
        function() {
            return this.item.margin
        },
        function() {
          // unmount other watchers which can cause bounce effect
          this.updateSell()
          // calculate sell price and update
          this.setSellPrice()
          // re-add watchers
          this.resetWatchers()
        }
      ),

      this.updateSell = this.$watch(
        function() {
            return this.item.sell
        },
        function(sellPrice) {
          // unmount other watchers which can cause bounce effect
          this.updateMargin()
          // update margin
          this.setMargin(sellPrice)
          // re-add watchers
          this.resetWatchers()
        }
      )
    },

    setSellPrice() {
      let price = (100 / (100 - this.item.margin)) * this.item.net
      this.item.sell = price.toFixed(2)
    },

    setMargin(sellPrice) {
      let profit = (sellPrice - this.item.net)
      let price = (100 * profit) / sellPrice
      this.item.margin = price.toFixed(2)
    }
  }

})

new Vue({
  el: '#vue',
  data: {
    prices: [
        { 
        id: 1,
        net: 5,
        margin: 10,
        sell: 5.56
      },
        { 
        id: 2,
        net: 7,
        margin: 10,
        sell: 7.78
      },      
    ]
  }
})

In my understanding, I believe I am utilizing the watchers correctly by mounting them on mounted() and calling a method. Then, re-initializing by recalling that method?

Your assistance in resolving this issue would be greatly appreciated.

Answer №1

Here's a clever solution that utilizes computed values

Each parameter (net, margin, sell) is abstracted through a computed value. The getter returns the this.item value, while the setter first updates the this.item value and then updates the related values.

This issue is akin to that of a color picker. For a more intricate example of this problem, check out this link

Vue.component('pricing', {
template: '#pricing-row',
  props: ['item'],
  computed: {
  net:{
    get () {
      return Number(this.item.net)
      },
      set (net) {
      this.item.net = Number(net)
        this.setSellPrice()
      }
    },
  margin:{
    get () {
      return this.item.margin
      },
      set (margin) {
      this.item.margin = Number(margin)
        this.setSellPrice()
      }
    },
  sell:{
    get () {
      return this.item.sell
      },
      set (sell) {
      this.item.sell = Number(sell)
      this.setMargin()
      }
    }
  },
  methods: {
    
    setSellPrice() {
      let price = (100 / (100 - this.margin)) * this.net
      this.item.sell = price.toFixed(2)
    },
    
    setMargin() {
      let profit = (this.sell - this.net)
      let price = (100 * profit) / this.sell
      this.item.margin = Number(price.toFixed(2))
    }
  }
  
})

new Vue({
  el: '#vue',
  data: {
  prices: [
    { 
      id: 1,
        net: 5,
        margin: 10,
        sell: 5.56
      },
    { 
      id: 2,
        net: 7,
        margin: 10,
        sell: 7.78
      },      
    ]
  }
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.5.5/vue.min.js"></script>
<script type="text/x-template" id="pricing-row">
  <tr>
  <td><input v-model="net" /></td>
    <td><input v-model="margin"  /></td>
    <td><input v-model="sell"  /></td>
  </tr>
</script>


<div id="vue">
  <table>
    <tr>
      <th>Net</th>
      <th>Margin</th>
      <th>Price</th>
    </tr>
    <tr is="pricing" v-for="(price, index) in prices" :item="price" :key="price.id"></tr>
  </table>
</div>

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

Storing $i18n.locale in Vuex: A Simple Guide

Implementing language selection with a drop-down list (using kazupon/vue-i18n plugin): <select v-model="$i18n.locale" class="nav__lang-switcher"> <option v-for="(lang, i) in langs" :key="`lang${i}`" :value="lang.value">{{ lang.label }}</o ...

What is the best way to transfer a JavaScript variable through a query string from one HTML page to another?

Is there a way to pass a JavaScript variable called username from one HTML page, example1.html, to another HTML page, example2.html, using query strings? <script type="text/javascript" > $(document).ready(function() { $('#SubmitForm ...

Guide on uploading a 3D model in JSON format to Three JS

I am trying to import a JSON file that contains information about a 3D model for Three JS. I have the basic code structure for Three JS and also have a loader function: const loader = new THREE.ObjectLoader(); loader.load( // resource URL "mo ...

An issue arises when using JSON.parse() with regular expression values

I am encountering an issue with parsing a JSON string encoded with PHP 5.2 json_encode(). Here is the JSON string: {"foo":"\\."} Although this JSON string is valid according to jsonlint.com, when using the native JSON.parse() method in Chrome a ...

Ajax request not populating controller with data in ASP.NET CORE MVC

`Hello everyone, I'm running into a problem with my colleague's assignment and could really use some assistance. The issue pertains to ASP.NET Core MVC. I have an API Controller for editing student groups. This API Controller receives a GroupView ...

Regularly updating a book's interactive pages with turn.js technology

I experimented with generating dynamic content in turn.js using the sample provided here. This is an excerpt of the code I have written: <body> <div id="paper"> </div> </body> <script type="text/javascript"> $(win ...

Application suddenly crashes due to a severe issue: FATAL EXCEPTION: java.lang.RuntimeException, preventing the activity from starting

I recently updated my Ionic, Angular, and Capacitor application to the latest versions - Ionic 7, Angular 16, and Capacitor 5. After the update, I noticed that on Android, the app works fine when installed for the first time. However, upon restarting the a ...

Error in SO Embed Snippet Fiddle due to Bootstrap 4 JS Issue

Just wondering, any idea why the bootstrap 4 js is throwing this error: https://i.sstatic.net/J4Iq4.png when trying to embed the snippet? (No errors in the external Fiddle) Added tether.js but no luck (kept it commented). Switched to jQuery 2.2.1 on th ...

Displaying search results seamlessly on the same page without any need for reloading

I am looking to create a search engine that displays results without the need to refresh the page. I have come across using hash as a potential solution, but I don't have much knowledge about web programming. So far, with the help of tutorials, I have ...

How to use jquery and ajax to retrieve an array of data and show it on the screen

I am facing an issue with my ajax request. Actually, I am unsure of how to fetch multiple records. I attempted the following: $rqt = "SELECT a,b,c from table"; $res = mysql_query($rqt); while ($data = mysql_fetch_assoc($res)): $objet = $d ...

Encountering an issue with finding the module `scheduler/tracing` in React Native

Encountering an error during the react-native run-android process: Error: Unable to resolve module `scheduler/tracing` from `/Users/miftahali/projects/react/appscustomec/node_modules/react-native/Libraries/Renderer/oss/ReactNativeRenderer-dev.js`: Module ...

How can I make Requirejs and Threejs OrbitControls work together?

Having trouble implementing OrbitControls with requirejs. Here's my configuration: I attempted to follow guidance from this post on Stack Overflow RequireJS and THREE.js Orbit Controls, but it's not working. requirejs.config({ baseUrl: &ap ...

What is the best approach to accessing a key within a deeply nested array in JavaScript that recursion cannot reach?

After hours of research, I have come across a perplexing issue that seems to have a simple solution. However, despite searching through various forums for help, I have reached an impasse. During my visit to an online React website, I stumbled upon the web ...

Retrieve the URI data from the response object using Axios

Currently, I'm in the process of transitioning a node project from utilizing request.js to incorporating axios.js While using the request package, extracting URI data from the response object can be achieved like so: request(req, (err, response) =&g ...

Redirect in ExpressJS after a DELETE request

After extensive searching, I am still unable to figure out how to handle redirection after a DELETE request. Below is the code snippet I am currently using WITHOUT THE REDIRECT: exports.remove = function(req, res) { var postId = req.params.id; Post.re ...

step-by-step guide on transferring the text content of an HTML paragraph element to another HTML paragraph element through JavaScript in ASP.NET

I'm looking for help with passing the text value from one HTML paragraph element to another when a JavaScript function is called. The function loads a div element with an enlarged image and a paragraph content. Below is the code I am using: JavaScrip ...

The functionality of jQuery $.fn is not recognized

Why is my code being directly DOWN VOTED? Am I missing something since $.fn. is not functioning correctly? Oddly enough, this functionality works perfectly in another module. I encountered a strange error in jQuery. I am attempting to crop an image using ...

Issues with dynamically loading jQuery arise specifically on certain websites

Code: initializeJQuery(); function initializeJQuery() { if (typeof jQuery === "undefined") { var scriptElement = document.createElement('script'); scriptElement.setAttribute("type", "text/javascript"); scriptElement.setAttribute("sr ...

Exploring the growth of CSS offsetting alongside with AngularJS

I am working on an Angular app where I need to increase the left offset of a div by 90px every time the slideThis() function is called. In jQuery, I would typically achieve this using left: '+=90', but I'm struggling to find a similar method ...

Preserving the active menu item in Nuxt and Vue with Element UI when the browser back button is clicked

Hey there, I'm facing an issue with a clicked menu item that shows a 'selected' state by darkening the item for user feedback. The problem arises when the active item gets reset upon pressing the browser back button, even though the route ch ...