Rob
Rob

Reputation: 1636

Form number input does not work with keys

<template v-for="(paint, index) in paints">
 <input type="number" v-bind:min="1" v-model.number="paint.qty">
</template>

-

var paintListApp = new Vue({
    delimiters: ['${', '}'],
    el: '#paintListApp',
    data: {
        paints: paints
    },
    methods: {
        addToSet: function(sku, name, image) {
            // method triggered when item is clicked - sends data to event bus
            this.$eventHub.$emit('addToSelectedPaints', sku, name, image)
        }
    }
});

var paintWidget = new Vue({
    el: '#paintWidget',
    delimiters: ['${', '}'],
    data: {
        paints: []
    },
    created() {
        // data picked up - processed by 'addToSelectedPaints'
        this.$eventHub.$on('addToSelectedPaints', this.addToSelectedPaints);
    },
    methods: {
        addToSelectedPaints: function (sku, name, image) {
          var skuIndex = _.findIndex(this.paints, function (o) { return o.sku === sku; });
          if (skuIndex !== -1) {
            this.paints[skuIndex].qty = this.paints[skuIndex].qty + 1;
          } else {
            this.paints.push({
              sku: sku,
              name: name,
              image: image,
              qty: 1
            });
          }
      }
    }
});

Trying to get min values to work on number inputs. The min is respected by the browser number plus / minus controls - however, when using the keyboard, the min attribute appears to be ignored. I've tried all sorts of things from adding a method triggered by keyup etc and testing the value, through to watchers.

Keyup gets messy as when deleting, it automatically added a 1... making it difficult to type numbers above 19... (eg, you backspace to enter 2, but - it inserts a 1).

I just need to get native browser input min attribute working with keyboard input.

** Edit **

<input type="number" v-model="paint.qty" @change="paint.qty = paint.qty < 1 ? 1 : paint.qty">

Sort of solves the issue, albeit at the expense of the min attribute. Hooking into the @change event. If input is less than 1, switch it for 1. It also doesn't update until the input has lost focus - not locking the ui up. So not exactly the way I wanted it to work - but the result is the same.

** edit **

I've adapted Richard Matsens answer (the accepted one) to use an input and timeout... this behaves a bit more like the Chrome and Firefox native implementation.

<input type="number" min="1" v-model.number="paint.qty" @input="handleUpdate($event, index)">

and in the handleUpdate method:

  ...handleUpdate(event, index) {
    var updater;
    clearTimeout(updater);

    this.currentIndex = index;
    var paints = this.paints;
    var max = this.max;

    updater = setTimeout(function() {
      if(event.target.value < event.target.min) {
        paints[index].qty = parseInt(event.target.min);
      }
      if(event.target.value > max){
        console.log(max);
        paints[index].qty = parseInt(max);
      }
    }, 1000);
  }...

clearing the timeout to prevent the updater bit firing too many times - bouncing / mashing etc...

Upvotes: 2

Views: 2892

Answers (1)

Richard Matsen
Richard Matsen

Reputation: 23483

From this Validate input type number with range min/max

Most browsers “ignore” (it’s their default behavior) min and max, so that the user can freely edit the input field and type a number that’s not in the range 1-5.

From this How to detect changes in nested data, can use an @input on the control and a method() to handle the check.

Works for min="0", but say min="1" may be problematic if the user wants to type in "11".

Changed to blur event to handle above caveat.

methods: {
  handleUpdate(event, index) {
    if(event.target.value < event.target.min) {
      this.paints[index].qty = event.target.min;
    }
  }
},

also add @blur() to the input

<div >
  <input v-for="(paint, index) in paints" 
    @blur="handleUpdate($event, index)"
    type="number" min="2" v-model.number="paint.qty">
</div>

For completeness, you may also want to add a validation message so that the user knows why the input value is being changed.

Upvotes: 1

Related Questions