How to detect programmatic value change on input field

时间:2016-08-31 12:32:51

标签: javascript html validation input event-handling

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.

2 个答案:

答案 0 :(得分:1)

您可以在更改值之后以类似方式触发事件

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>

答案 1 :(得分:0)

所以,对我来说,你的事件监听器根本没有触发,因为它们没有发生。当以编程方式更改值时,字段上没有“keydown”,因为在DOM中没有触发任何事件。

对我来说,我认为你应该连接一些其他的事件处理程序以及更多的“页面级别”。查看jQuery事件类别(https://api.jquery.com/category/events/)如果将这些事件分配给页面本身 - 在鼠标x \ y更改时,在页面上输入\离开和焦点\模糊。

使用所有这些事件似乎有点过分,但这似乎是一个独特的案例。对我来说,你永远不会真正信任用户输入,所以我倾向于在用户提交时重新计算\验证数据,但是对于没有提交给你的数据,我认为通过某些页面级事件触发这些项目比输入特定的事件可能会让你超过驼峰......