Prepare for a thorough cross-referencing session

In my attempt to create a tool with 3 inputs that are interdependent - "Earn %", "Earn $" and "Own Price".

Initially, the default value for "Earn percentage" is set at "10", making the initial calculation function as intended. Changing this one value automatically adjusts the other two because there are no circular references: https://jsfiddle.net/2m971kur/2/

const app = new Vue({
  el: '#app',
  data: {
        exVAT: 1500,
        retailPrice: 2900,
        earnPercentage: 10
  },
    computed: {
        incVAT() {
            return this.exVAT * 1.25;
        },
        ownPrice() {
            return this.exVAT + (this.exVAT * (this.earnPercentage / 100));
        },
        earnAmount() {
            return this.ownPrice - this.exVAT;
        }
    }
})

However...
When attempting to introduce circular references, my code encounters issues: https://jsfiddle.net/xrwykvg5/

const app = new Vue({
  el: '#app',
  data: {
        exVAT: 1500,
        retailPrice: 2900,
        earnPercentage: 10,
        ownPrice: 0,
        earnAmount: 0
  },
    watch: {
        earnPercentage() {
            this.earnAmount = this.exVAT * (this.earnPercentage / 100);
            this.ownPrice = this.exVAT + this.earnPercentage;
        },
        ownPrice() {
            this.earnAmount = this.ownPrice - this.exVAT;
            this.earnPercentage = 100 / (this.ownPrice / this.exVAT);
        },
        earnAmount() {
            this.ownPrice = this.exVAT + this.earnAmount;
            this.earnPercentage = (this.ownPrice / this.exVAT) * 100;
        }
    }
})

How can I resolve this issue?

While the example was created using Vue.js, showcasing a simple demonstration of the problem, my actual code is in Angular 2.

Answer №1

Trust Roy J's skills to create a clean and concise solution with computed properties.

Admittedly, I took the easy way out. I lacked the courage to fully comprehend your logic and opted for a simple method-based approach:

const app3 = new Vue({
  el: '#app',
  data: {
    incVAT: 0,
    exVAT: 1500,
    retailPrice: 2900,
    earnPercentage: 10,
    ownPrice: 0,
    earnAmount: 0
  },
  methods: {
    changeEarnPercentage(earnPercentage) {
      this.earnPercentage = Number(earnPercentage);
      this.earnAmount = this.exVAT * (this.earnPercentage / 100);
      this.ownPrice = this.exVAT + this.earnPercentage;
    },
    changeOwnPrice(ownPrice) {
      this.ownPrice = Number(ownPrice);
      this.earnAmount = this.ownPrice - this.exVAT;
      this.earnPercentage = 100 / (this.ownPrice / this.exVAT);
    },
    changeEarnAmount(earnAmount) {
      this.earnAmount = Number(earnAmount);
      this.ownPrice = this.exVAT + this.earnAmount;
      this.earnPercentage = (this.ownPrice / this.exVAT) * 100;
    }
  }
})
#app div {
  float: left;
  margin: 1em;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
  <div>
    Inc. VAT: <br>{{ incVAT }}
  </div>
  <div>
    Ex. VAT: <br>{{ exVAT }}
  </div>
  <div>
    % earned: <br>
    <input type="text" :value="earnPercentage" @input="changeEarnPercentage($event.target.value)" />
  </div>
  <div>
    $ earned: <br><input type="text" :value="earnAmount" @input="changeEarnAmount($event.target.value)" />
  </div>
  <div>
    Own price: <br><input type="text" :value="ownPrice" @input="changeOwnPrice($event.target.value)" />
  </div>
  <div>
    Retail: <br>{{ retailPrice }}
  </div>
</div>

All in all, not too shabby.

It's worth noting that I used some Number() conversions to avoid treating numbers as strings. Additionally, utilizing an <input type="number"> would be a wise choice.

Answer №2

In order to properly use v-model on your computed values, it is essential for them to have setters defined. The set function should essentially be the inverse of the get function to ensure that the input and output align correctly. This issue can be observed in Cobaltway's example where slight changes in Own Price result in significant jumps in % Earned, showcasing inconsistent results due to improper formulation.

this.ownPrice - this.exVAT;

For instance, for the earnAmount, with the get value above, the corresponding set function would be:

this.ownPrice = Number(newValue) + this.exVAT;

Note that a conversion from text to number is required here. By setting up ownPrice similarly (and utilizing v-model.lazy), you can create a structured approach as shown below:

const app3 = new Vue({
  el: '#app',
  data: {
    exVAT: 1500,
    retailPrice: 2900,
    earnPercentage: 10
  },
  computed: {
    incVAT: function() {
      return this.exVAT * 1.25;
    },
    earnAmount: {
      get: function() {
        return this.ownPrice - this.exVAT;
      },
      set: function(newValue) {
        this.ownPrice = Number(newValue) + this.exVAT;
      }
    },
    ownPrice: {
      get: function() {
        return this.exVAT + (this.exVAT * (this.earnPercentage / 100));
      },
      set(newValue) {
        this.earnPercentage = 100 * (Number(newValue) - this.exVAT) / this.exVAT;
      }
    }
  }
});
#app div {
  float: left;
  margin: 1em;
}
<script src="//cdnjs.cloudflare.com/ajax/libs/vue/2.3.4/vue.min.js"></script>
<div id="app">
  <div>
    Inc. VAT:
    <br>{{ incVAT }}
  </div>
  <div>
    Ex. VAT:
    <br>{{ exVAT }}
  </div>
  <div>
    % earned:
    <br>
    <input type="text" v-model.lazy="earnPercentage" />
  </div>
  <div>
    $ earned:
    <br>
    <input type="text" v-model.lazy="earnAmount" />
  </div>
  <div>
    Own price:
    <br>
    <input type="text" v-model.lazy="ownPrice" />
  </div>
  <div>
    Retail:
    <br>{{ retailPrice }}
  </div>
</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

Tips for customizing the appearance of a React-Table header when sorting data

How can I change the header's background color in react-table based on a selected item? For example, if I click on ID, the ID header should change its background color to red. I have tried various methods to update the background color upon selection ...

Instructions on converting XML data obtained from an AJAX call into a downloadable file

I've been struggling with converting an AJAX response containing XML text into a downloadable file. I've tried various methods but haven't had success. In the past, I was able to work with a similar scenario involving a pdf, where the conte ...

The most efficient method for handling a vast amount of data in NodeJS

My database consists of 4 million numbers and I need to quickly check if a specific number exists in it. Example of the database: [177,219,245,309,348,436,...] I initially tried using a MySQL table for this task, but it took a lengthy 1300ms just to chec ...

The jqGrid displays a plus sign even when the subgrid is empty while using XML

I am utilizing jqGrid to display data with a subgrid in XML format. $("#UDFs").jqGrid({ ajaxGridOptions: { contentType: 'application/xml; charset=utf-8' }, datatype: 'xmlstring', datastr: data, xmlReader: { root: "Respo ...

Converting milliseconds into a formatted DateTime using AngularJS: A step-by-step guide

Upon receiving JSON data from the server, I obtained a date-time in milliseconds: $scope.JDT = "1492499995056";. While I am able to display the scope variable 'JDT' on my view using a filter: {{JDT | date:"dd/MM/yyyy h:mm:ss a"}} ... I do not a ...

Tips for creating a stylish scrollbar in a React Material-Table interface

Currently, I am utilizing the react material-table and looking to implement a more visually appealing scroll-bar instead of the default Pagination option. Although I have experimented with the react-custom-scroll package, it has not produced the desired ...

Find and return a specific record from MongoDB if it matches the exact value

model.js import mongoose from 'mongoose'; const { Schema, Types } = mongoose; const participants = { user_id: Types.ObjectId(), isAdmin: Boolean } const groupSchema = new Schema({ id: Types.ObjectId(), // String is shorthand for {type: St ...

Eliminate operation in React with the help of Axios

Within my React application, I have implemented a callback method for deleting data from an API using the axios library: deleteBook(selectedBook) { this.setState({selectedBook:selectedBook}) axios.delete(this.apiBooks + '/' + this.select ...

The Jquery .clone() function presents issues in Internet Explorer and Chrome browsers, failing to perform as expected

I need to duplicate an HTML control and then add it to another control. Here is the code I have written: ko.bindingHandlers.multiFileUpload = { init: function (element, valueAccessor, allBindingsAccessor, viewModel, bindingContext) { va ...

Exploring the depths of JSON using @attributes and @association in the realm of JavaScript and AngularJS

Currently, I am working on a project that involves utilizing an API for data retrieval, updates, and deletions. The API in question is the prestashop API. While I have managed to retrieve data and update certain items successfully, I encountered an issue. ...

Encountering difficulties with image processing on a web page

Recently, I've been experimenting with uploading an image and converting it to a grayscale version on my webpage. Oddly enough, the javascript code works perfectly when tested locally but fails to generate the grayscale image once integrated onto the ...

Steps to display page content only after running Java code in JSP

The webpage index.jsp is responsible for retrieving images and text data from a database using Java code. Within the JavaScript file, I have included: $(document).ready(function(){ //When Document is Ready, Show the Main Page $("#showifjavaenable ...

Invoke a function in Angular when the value of a textarea is altered using JavaScript

Currently, I am working with angular and need to trigger my function codeInputChanged() each time the content of a textarea is modified either manually or programmatically using JavaScript. This is how my HTML for the textarea appears: <textarea class ...

Customize vue.config.js and webpack 4: modify the 'exclude' or 'include' parameters of a rule

I'm trying to customize the exclude/include parameters of a webpack rule in a project created using vue-cli-service. Since it only has a vue.config.js, I can access the configuration using chainWebpack, but modifying the rule directly is proving to be ...

Steps to trigger an AngularJS modal window when the URL contains a query string

I am in the process of creating a website and I would like to have a $uiModal open when there is a querystring in the URL. If there is no query string, then the modal should not open. Here is the code snippet: myApp.controller('jobObjectiveController ...

Provide a unique <li> attribute for the JavaScript function to utilize

Is there a way to pass specific attributes from dropdown options to a javascript function? I have tried using .data() and .attr(), but the console keeps showing "undefined". Any suggestions on how to achieve this in a cleaner and simpler way would be gre ...

Validating checkboxes using HTML5

When it comes to HTML5 form validation, there are some limitations. For instance, if you have multiple groups of checkboxes and at least one checkbox in each group needs to be checked, the built-in validation may fall short. This is where I encountered an ...

Error occurred while making a request in React using Axios: TypeError - Unable to retrieve the 'token' property as it is undefined

After successfully receiving a token from logging in with React Redux, I attempted to authorize it using the token. However, an error occurred stating Axios request failed: TypeError: Cannot read property 'token' of undefined. The token is stored ...

Executing Two Distinct JQuery Api Requests

I'm facing a challenge with integrating the data from two different API calls and processing them together. After receiving JSON responses from both calls, I convert them into GeoJSON format. The next step is to combine these geojson objects in anothe ...

Demonstration of using .queue() and .dequeue() in relation to $.queue() and $.dequeue()

I successfully completed an animation using animate(), queue(), and dequeue(). However, I recently discovered that jQuery also offers jquery.queue() or $.queue() and jquery.dequeue() or $.dequeue(). Can anyone assist me in understanding these new terms w ...