2

I've read several questions [1], [2], [3] regarding this topic, but none seems to provide a general solution to this problem. All answers seems to be directed to some specific cases.

I have this simple input field

<input type="number" id="inputBox" min="0" max="255" step="1" />

and I do a strict input validation on it:

inputBox.addEventListener("input", function () {
    validateInput(this);
});

inputBox.addEventListener("keydown", function (e) {
    validateInput(this, e);
});

function validateInput(elm, e) {
    // handle keydown event
    if (e) {
        // do not allow floating-point numbers, if it's not expected
        if (!isFloat(elm.step)) {
            if (e.key == ".") {
                e.preventDefault();
            }
        }
    }
    // handle input event
    else {
        // do not allow leading zeros
        while (elm.value.length > 1 && elm.value[0] === "0") {
            elm.value = elm.value.toString().slice(1);
        }
        // input should be between min and max
        if (elm.validity.rangeUnderflow) {
            elm.value = elm.min;
        }
        else if (elm.validity.rangeOverflow) {
            elm.value = elm.max;
        }
    }
}

All this seems to be working fine for user input.

var inputBox = document.getElementById("inputBox");

inputBox.addEventListener("input", function() {
  validateInput(this);
});

inputBox.addEventListener("keydown", function(e) {
  validateInput(this, e);
});

function validateInput(elm, e) {
  // handle keydown event
  if (e) {
    // do not allow floating-point numbers, if it's not expected
    if (!isFloat(elm.step)) {
      if (e.key == ".") {
        e.preventDefault();
      }
    }
  }
  // handle input event
  else {
    // do not allow leading zeros
    while (elm.value.length > 1 && elm.value[0] === "0") {
      elm.value = elm.value.toString().slice(1);
    }
    // input should be between min and max
    if (elm.validity.rangeUnderflow) {
      elm.value = elm.min;
    } else if (elm.validity.rangeOverflow) {
      elm.value = elm.max;
    }
  }
}

function isFloat(f) {
  var f = parseFloat(f);
  var floor = Math.floor(f);
  var fraction = f - floor;
  if (fraction > 0) {
    return true;
  }
  return false;
}
<input type="number" id="inputBox" min="0" max="255" step="1" />

But the user can still modify the input field value programmatically. The user can enter the following values through the console to bypass the validation and these are invalid/unexpected values:

inputBox.value = "005";
inputBox.value = "2.5"
inputBox.value = "-05.5";

An ideal solution to this would be to call a function (e.g. validateProgrammaticInput()) if the user changes the field value using inputBox.value.

inputBox.value = -10; // magically call validateProgrammaticInput()

Note: I'm not using a form. There's no submit button. This will not be sent to a server. This is a client application. Value should be validated in real-time. If I want to modify the field value programmatically, I can trigger a custom event in my code to validate the input, but that's not the case. What I want is to validate the input, if the user enters it programmatically. So my use case is irrelevant to the problem. Thought I should point these out before a confusion.

Community
  • 1
  • 1
akinuri
  • 7,673
  • 10
  • 47
  • 80

2 Answers2

1

you can trigger the event programmaticaly after changing the value like this

var inputBox = document.getElementById("inputBox");
inputBox.addEventListener("input", function () {
  console.log("input");
    // input should be between min and max
    if (this.validity.rangeUnderflow) {
        this.value = this.min;
    }
    else if (this.validity.rangeOverflow) {
        this.value = this.max;
    }
    // do not allow leading zeros
    while (this.value.length > 1 && this.value.toString()[0] === "0") {
        this.value = this.value.toString().slice(1);
    }
});

inputBox.addEventListener("keydown", function (e) {
    // do not allow floating-point numbers, if it's not expected
    if (!isFloat(this.step)) {
        if (e.key == ".") {
            e.preventDefault();
        }
    }
},false);

function change(){
  inputBox.value = "005";
  inputBox.dispatchEvent(new Event('input'));
}

function isFloat(n){
    return Number(n) === n && n % 1 !== 0;
}
<input type="number" id="inputBox" min="0" max="255" step="1" />

<button onclick="change()">change</button>
coding-dude.com
  • 526
  • 5
  • 18
  • See the note at the bottom of my question, please. – akinuri Aug 31 '16 at 13:20
  • Not sure what you mean by "the user enters it programmatically", however, you can use a setInterval() to validate the value of the field at regular intervals – coding-dude.com Aug 31 '16 at 13:30
  • Also, your `isFloat()` function, or rather [kennebec's](http://stackoverflow.com/a/3886106/2202732), expects `n` to be a number. You can't validate an input value (which is a string) with it directly. See this [test](https://jsfiddle.net/akinuri/4eb9pr6k/). However, [mine](http://stackoverflow.com/a/39104929/2202732) is prepared for multiple cases. – akinuri Aug 31 '16 at 13:36
  • "the user enters it programmatically" means that one can open the console and change the value there to bypass the validation. – akinuri Aug 31 '16 at 13:38
0

So, to me, your event listeners aren't triggered at all because theyre not occurring. There's no "keydown" on the field when the values are changed programmatically, as no events are triggered in the DOM.

To me, I think you should wire some other event handler as well that's more "page level". In looking at the jQuery event categories (https://api.jquery.com/category/events/) what if you assigned these events to the page itself - on mouse x\y changing, on page enter\leave and focus\blur.

It may seem a little overboard to use all of these events, but this seems to be a unique case. To me, you never really trust user input, so I tend to recalculate\validate data when submit by the user, but for this scenario where the data isn't being submitted to you, I think triggering these items by some page level events rather than input specific events may get you over the hump...

ewitkows
  • 3,293
  • 3
  • 36
  • 55