Synchro
Synchro

Reputation: 1269

Vue JS How to bind the onChange event to change the value in input

I am using npm package vue-range-component with which I change the value with a slider and then that value is reactively changed in the input

My problem is that I can’t apply the onChange event for inputs, I need to be able to change the value in the input, for example, put the number 70, and then this number was applied to the vue-range-component, something like that

Here is my sandbox code

enter image description here

<template>
  <div class="app-content">
    <div>
        <input type="text" v-model="value[0]" />
        <input type="text" v-model="value[1]" />
    </div>

    <vue-range-slider
      v-model="value"
      :min="min"
      :max="max"
      :formatter="formatter"
      style="margin-top: 40px"
    ></vue-range-slider>

    <div class="multi-range-value-container">
        <p>{{ value[0] }}</p>
        <p>{{ value[1] }}</p>
    </div>
    </div>
</template>

<script>
import "vue-range-component/dist/vue-range-slider.css";
import VueRangeSlider from "vue-range-component";

export default {
  data() {
    return {
      value: [0, 100],
    };
  },

  methods: {
    onChange(event) {
      console.log(event.target.value);
    },
  },

  components: {
    VueRangeSlider,
  },
  created() {
    this.min = 0;
    this.max = 1000;
    this.formatter = (value) => `$${value}`;
  },
};
</script>

Upvotes: 2

Views: 24624

Answers (2)

Michal Lev&#253;
Michal Lev&#253;

Reputation: 37793

It is indeed Vue reactivity issuse

You can fix it by not using v-model syntactic sugar but split it like this:

From:

<input type="text" v-model="value[0]" />

to:

<input type="text" :value="value[0]" @input="changeRange(0, $event.target.value)" />

define a method:

methods: {
  changeRange(index, value) {
    const v = parseInt(value, 10) // value from input is always string
    this.$set(this.value, index, v)
  }
}

Update

Above code is a fix you would need anyway but unfortunately the vue-range-component has a different issue as it blocks all user keyboard input to any input element on the same page - see this and this issue

It was already fixed by this pull request but it wasn't released yet to npm

You can use some of the workarounds described in the issues BUT given the way how the maintainer (not) handles the issue, it would be probably better for you to look around for another component with similar functionality...

Upvotes: 1

Jordan
Jordan

Reputation: 2371

One caveat of Vue's reactivity system is that you cannot detect changes to an array when you directly set the value of an item via its index.

As explained in the link, there are two main methods of making array modifications reactive:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)

// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

Using these methods forces the VueJS reactivity system to update its state.

To implement this solution in your example, you can use a watcher on a modelled value, an @change event or a @keyup event.

A watcher is likely the most resource intensive approach. I would suggest using @keyup (which would fire on every keypress as opposed to when you unfocus the input with @change) and then debouncing the input if the value is used to filter/sort/load anything.

If you wanted to as well, you could also directly set the entire array.

For example instead of setting value[0] = something you could do value = [...value, something];and this would be reactive.

Upvotes: 3

Related Questions