10

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')
10
  • i've tried ton iput 80, as you told, but both shows 50, like code says do Commented Aug 2, 2017 at 15:09
  • First input 60 then click outside the box to trigger blur then re click in the box to put 80 Commented Aug 2, 2017 at 15:11
  • nshow 50 not 80 Commented Aug 2, 2017 at 15:12
  • I'm not sure I understand what you mean. Have you followed the steps? Don't you get the same thing as I posted? Commented Aug 2, 2017 at 15:18
  • 2
    @Leo Oke, but using a computed property as an input-model feels like an anti-pattern to me. There is a reason why they are getters only by default. The main purpose is to cache the result of an operation and only recalculate when the underlying data property changes. Not to use that result as a reactive model. Besides, using the result of a computation as input makes validation much harder because of the string appending. Commented Aug 2, 2017 at 17:24

3 Answers 3

7

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')
Sign up to request clarification or add additional context in comments.

3 Comments

That is why I put this.enteredValue = 0; so enteredValue changes
@Leo yes but not works fine every time, not deteds window changed to update it
I wanted to used the computed property but I ended using it as a variable as you suggested.
2

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";
             }
      },

2 Comments

I like it but try to enter 500000 by keeping the 0 down. You would be able to get 50000 in the box and 50 as the value
You're right, this is the same problem as previously I'll mess a bit with the code to find a better solution
1

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
      }
  }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.