3

I have an input element that bind with v-model to a item value, I want to limit the user input to just type numeric value on range between 0 to 10, I was tried this thing before(add @input and check the input value to keep it in range)

my code is like this:

<v-text-field @input="checkItem" v-model="item"></v-text-field>

checkItem(val) {
      if(parseInt(val) < 1) {
        this.item = 1;
      } else if(parseInt(val) >10) {
        this.item = 10;
      }
    }

Problem after first time we type number out of range the function works great and keep it in range but when we type out of range number again the element didn't update because the new item value is the same as the old item value! to solve this I try to use forceUpdate and the $forceUpdate() not work!!!

for example

  • if user type anything between range number into input, because it's in range everything is ok;

  • but if user type 0 or any number outside of range, on the first time item value change to 1 if value was under 1 but if again type any negative value because the item value last time was changed to 1 when we set it to 1 again nothing happening on the view and the element value was not updated.

The main question is how to force vue to update this input field value?

RonU
  • 5,525
  • 3
  • 16
  • 13
newvertex
  • 160
  • 3
  • 15
  • Have you tried watching for changes using a `watch` method rather than binding to input? Modifying the model data in an input hook is not intended usage of `v-model` – rh16 Feb 28 '19 at 00:32
  • @rh16 if you mean use :value to bind item value from data object and change the item on the watch from input change, I have to say yes I was tried this before and got the same problem(the view part is not update because of the value is not changed) – newvertex Feb 28 '19 at 01:30

2 Answers2

3
  <div><input type="number" v-model="item"></input></div>
</template>

<script>
export default {
  name: "ranges",

  data() {
    return {
      item: Number,
      error: String
    };
  },

  watch: {
    item(newVal, lastVal) {
      if (newVal > 10) this.item = 10
      if (newVal < 1) this.item = 1
    }
  }
};
</script>

Here using the watcher you can do that validation

mdiaz00147
  • 152
  • 2
  • 11
  • Thanks for answer, but I don't want to show a message to user, I want to replace the user input value with the correct one just when user is typing(the current code update the data object value but not update the view part of component, because the value is the same as before on data object then vue thinks no change was happened) – newvertex Feb 28 '19 at 01:26
  • @Mojtaba i've just updated the code to acomplish what you said, let me know if that is what you were looking for. – mdiaz00147 Feb 28 '19 at 02:19
  • Absolutely right and thank you But why sometimes something wrong with the second condition and accepts it to be zero ?!? – newvertex Feb 28 '19 at 02:38
  • Actually i have never used before the @input callback, may be there is the issue, i recommend you to use better in this cases watch methods or computed ones – mdiaz00147 Feb 28 '19 at 02:46
  • And the main update problem was not solved!, when we try to type 0 into input first time it's update to 1 but after that the value on the vue-devtool is 1 but on the screen input element have the 0 value! and also if we type max value like 1000 give the same problem. then we need to rerender the input element to keep it update – newvertex Feb 28 '19 at 02:47
  • Are you sure ? take a look here with those examples you gave me . https://codesandbox.io/s/2vl035z37y i tested there and works well – mdiaz00147 Feb 28 '19 at 02:59
1

The only way to force the reactivity when the the final result is always the same, is to re-render the component for it to reflect the changes by updating its key.

Reference link here.

I have forked the sample Vue project from mdiaz00147, and modify into this, and I think it works as the author intended it to be.

Solution Code modified from mdiaz00147 's code snippet

<template>
  <div>
    <input :key="inputKey" v-model="item" @change="checkItem" />
  </div>
</template>

<script>
export default {
  name: "ranges",

  data() {
    return {
      item: null,
      inputKey: 0,
    };
  },

  methods: {
    checkItem() {
      if (parseInt(this.item) < 1) {
        this.item = 1;
      } else if (parseInt(this.item) > 10) {
        this.item = 10;
      }
      this.inputKey += 1;
    },
  },
};
</script>
Darky WC
  • 131
  • 2
  • 12