Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Vue.js - Input, v-model and computed property

Tags:

vuejs2

I'm using vue-2.4 and element-ui 1.4.1.

Situation

I have a basic input which is linked with v-model to a computed property. When blur I check if the value input is greater or lower than min and max and I do what I have to do ... Nothing fancy here.

Problem

The value displayed in the input does not always equal enteredValue

Steps to reproduce

1) Input 60 --> Value displayed is the max so 50 and enteredValue is 50 (which is ok)

enter image description here

2) Click outside

3) Input 80 --> Value displayed is 80 and enteredValue is 50

enter image description here

Questions

How can I fix that so the value displayed is always the same as the enteredValue ?

Here is the minimal code to reproduce what I'm facing JSFIDDLE

    <div id="app">
  The variable enteredValue is {{enteredValue}}
  <el-input v-model="measurementValueDisplay" @blur="formatInput($event)"></el-input>
</div>

var Main = {
  data() {
    return {
      enteredValue: '',
      max: 50,
      min: 10
    }
  },
  computed: {
      measurementValueDisplay: {
          get: function () {
              return this.enteredValue + ' inchs'
          },
          set: function (newValue) {
          }
     },
  },
  methods: {
      formatInput($event) {
         let inputValue = $event.currentTarget.value;
         if (inputValue > this.max) { this.enteredValue = this.max}
         else if (inputValue < this.min) { this.enteredValue = this.min}
         else this.enteredValue = inputValue
      }
  }
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
like image 920
Léo Coco Avatar asked Aug 02 '17 15:08

Léo Coco


People also ask

Can we use computed property in V-model?

You can use computed properties to calculate and display values based on a value or set of values in the data model.

What is the difference between a computed property and methods in VUE JS?

Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that computed properties are cached based on their reactive dependencies.

What is the difference between watch and computed in VueJS?

Computed props can react to changes in multiple props, whereas watched props can only watch one at a time. Computed props are cached, so they only recalculate when things change. Watched props are executed every time.

What is the difference between V-model and V bind?

v-model is a two-way binding. v-bind is a one-way binding. v-model is used for binding form elements like inputs, radio buttons, textarea, checkboxes. It is used for binding data, attributes, expressions, class, styles.


Video Answer


3 Answers

In case anybody still needs a hack for this one, you can use a value that will always change ( for example a timestamp )

var Main = {
  data() {
    return {
      enteredValue: '',
      max: 50,
      min: 10,
      now: 1 //line added
    }
  },
  computed: {
      measurementValueDisplay: {
          get: function () {
              return (this.now - this.now + 1 ) * this.enteredValue + ' inchs'; //line changed
          },
          set: function (newValue) {
              this.now = Date.now(); //line added
          }
     },
  },
  methods: {
      formatInput($event) {
         let inputValue = $event.currentTarget.value;
         if (inputValue > this.max) { this.enteredValue = this.max}
         else if (inputValue < this.min) { this.enteredValue = this.min}
         else this.enteredValue = inputValue
      }
  }
}
like image 136
Lucian Filote Avatar answered Oct 26 '22 07:10

Lucian Filote


Reading this vuejs, will understand what happens

"computed properties are cached based on their dependencies. A computed property will only re-evaluate when some of its dependencies have changed."

Changed some comportament of the code. Made run: computed() method not works properly for update value in window. But if looks at console the value yes updated. So, i remove computed (getter and setter), and put into data, without setter and getter( i dont like this in javascript).

var Main = {
  data() {
    return {
      measurementValueDisplay:'fff',
      enteredValue: '',
      max: 50,
      min: 10
    }
  },
  computed: {
      /*measurementValueDisplay: {
          get: function () {
              console.log('Computed was triggered so I assume enteredValue changed',this.enteredValue);
              return this.enteredValue + ' inchs'
          },
          set: function (newValue) {
          console.log('setter de qye', this.enteredValue);
          }
      },*/
  },
  methods: {
      formatInput($event) {
          this.enteredValue = 0;
          
          let inputValue = $event.currentTarget.value;
          console.log(inputValue);
          if (inputValue > this.max) { this.enteredValue = this.max}
          else if (inputValue < this.min) { this.enteredValue = this.min}
          else this.enteredValue = inputValue
          this.measurementValueDisplay = this.enteredValue + ' inchs'
          
          console.log(this.enteredValue, 'oioioioio0');
      }
   }
}
var Ctor = Vue.extend(Main)
new Ctor().$mount('#app')
like image 33
Álvaro Touzón Avatar answered Oct 26 '22 07:10

Álvaro Touzón


Your problem is that the values used in the computed property was not updated with the validation capping at 50 (Was 50, is now updated to 50, no need to recalculate), therefore v-model did not update the input.

I've edited your jsfiddle to use two computed properties:
One with an accessor to validate the entered value, one which returns the value with " inch" appended.

Here is the interesting part:

    computed: {
          measurementValueDisplay: {
              get: function () {
                  return this.enteredValue
              },
              set: function (newValue) {
                 this.enteredValue = 0;
                 let inputValue = parseInt(newValue);
                 if(Number.isNaN(inputValue)){this.enteredValue = this.min}
                 else if (inputValue > this.max) { this.enteredValue = this.max}
                 else if (inputValue < this.min) { this.enteredValue = this.min}
                 else this.enteredValue = inputValue
              }
         },
         valueWithInch(){
            return this.enteredValue + " inch";
             }
      },

like image 34
Antony Avatar answered Oct 26 '22 07:10

Antony