2

I have a vue (version 2.x) file where I have 3 fields - input1 x input2 = result

Now, when I change any one of them, the other two should be updated on the fly. I tried using watch property but that leads to infinite loop because the watchers keep calling each other.

Is there any vue related helper which I am missing here? Any help would be appreciated.

Refer this for example code.

<template>
  <input v-model="input1"></input>
  <input v-model="input2"></input>
  <input v-model="conversionRate"></input>
</template>

<script>
export default {
  data() {
    input1: null,
    input2: null,
    conversionRate: null
  },
  watch: {
    input1() {
      this.input2 = this.input1 * this.conversionRate
    },
    input2() {
      this.input1 = this.input2 * this.conversionRate
    },
    conversionRate() {
      this.input2 = this.input1 * this.conversionRate
    }
  }
}
</script>
6
  • what it is supposed to do with input1 and input2 if we edit result ? Commented Jun 13, 2018 at 11:13
  • I am basically doing a currency conversion. input2 is the conversion rate here. So to answer your question, if you edit the result, keep input2 fixed and change input1. Commented Jun 13, 2018 at 11:15
  • If everything is bound properly and you're using v-model, the fields should update automatically anyway. P.s Show some code. Commented Jun 13, 2018 at 11:20
  • I think you'll have to use @input and :value= instead of v-model and use intermediate values to prevent this effect of infinite loop. (currency1InputValue -> currency1, currency2InputValue -> currency2, etc...) Commented Jun 13, 2018 at 11:28
  • Let me write the basic code and add it in the question itself @webnoob Commented Jun 13, 2018 at 11:31

2 Answers 2

1

Since all three models are dependent on each other it causes an infinite loop.

As per your requirement you can use computed setter.

HTML

<div id="app">
  <input type="number" placeholder="amount" v-model="inputA"> X
  <input type="number" placeholder="rate" v-model="conversionRate"> =
  <input type="number" placeholder="total" v-model="total">
</div>

SCRIPT

new Vue({
  el: "#app",
  data: {
    total: 0,
    conversionRate: 1
  },
  computed: {
    inputA: {
      get() {
        return this.total / this.conversionRate;
      },
      set(newVal) {
        this.total = newVal * this.conversionRate;
      }
    }
  }
});

Here is the working fiddle

Sign up to request clarification or add additional context in comments.

2 Comments

this works just fine. But when I use Math.round, the get(),set() and get() gets called and it does not work as expected. Suppose if I change the total, the get() is called, which changes the inputA value, which calls set(), which in turn changes the total value again. So the value which I type gets changed. Can you help me with this situation?
inputA: { get() { return Math.round(this.total / this.conversionRate); }, set(newVal) { this.total = Math.round(newVal * this.conversionRate); } }
0

Your watcher at input2 is wrong which causes infinite loop (if the calulcation is based on float, you'd better to use Math.round), it should be:

input2: function (newVal) {
   this.input1 = newVal / this.conversionRate // not newVal*this.conversionRate
}

But @Vamsi Krishna should be an better solution.

The demo:

app = new Vue({
  el: "#app",
  data: function () {
    return {
      input1: null,
      input2: null,
      conversionRate: 1
    }
  },
  watch: {
    input1: function (newVal) {
      this.input2 = newVal * this.conversionRate
    },
    input2: function (newVal) {
      this.input1 = newVal / this.conversionRate
    },
    conversionRate: function (newVal) {
      this.input2 = this.input1 * newVal
    }
  }
})
<script src="https://unpkg.com/[email protected]/dist/vue.js"></script>
<div id="app">
  <input v-model="input1">
  <input v-model="input2">
  <input v-model="conversionRate">
</div>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.