15

Browser: Google Chrome V19.0.1084.52

I have a textbox which needs to be a number less than or equal to 255, on keydown I want to check if this value is above or equal to 255 else prevent the event.

In the Console when I console.log the event it will show event.srcElement.value as the value will appear i.e. from 12 => 123, when I console.log just event.srcElement.value it will show as the input was, not will be.

Console.log's are happening one after the other, nothing in between, no pauses.

How can I find what the new value of a textbox will be on keydown and why is the console.log returning different results?

Here's my code:

function inputNumeric(event,max) {

    console.log (event);
    console.log ('event.originalEvent.srcElement.value: '+event.originalEvent.srcElement.value);
    console.log ('event.srcElement.value: '+event.srcElement.value);

}

$("#rs485addr").keydown(function(event) {
    inputNumeric(event);
});

Console.log:

event.originalEvent.srcElement.value: 12
event.srcElement.value: 12

event.srcElement:

accept: ""
accessKey: ""
align: ""
alt: ""
attributes: NamedNodeMap
autocomplete: ""
autofocus: false
baseURI: "http://10.50.50.60/controller/?bid=10"
checked: false
childElementCount: 0
childNodes: NodeList[0]
children: HTMLCollection[0]
classList: DOMTokenList
className: "width-60"
clientHeight: 18
clientLeft: 2
clientTop: 2
clientWidth: 62
contentEditable: "inherit"
dataset: DOMStringMap
defaultChecked: false
defaultValue: "1"
dir: ""
dirName: ""
disabled: false
draggable: false
files: null
firstChild: null
firstElementChild: null
form: null
formAction: ""
formEnctype: "application/x-www-form-urlencoded"
formMethod: "get"
formNoValidate: false
formTarget: ""
hidden: false
id: "rs485addr"
incremental: false
indeterminate: false
innerHTML: ""
innerText: ""
isContentEditable: false
jQuery17102950612970162183: 22
labels: NodeList[1]
lang: ""
lastChild: null
lastElementChild: null
localName: "input"
max: ""
maxLength: 3
min: ""
multiple: false
name: ""
namespaceURI: "http://www.w3.org/1999/xhtml"
nextElementSibling: null
nextSibling: Text
nodeName: "INPUT"
nodeType: 1
nodeValue: null
offsetHeight: 22
offsetLeft: 183
offsetParent: HTMLBodyElement
offsetTop: 365
offsetWidth: 66
onabort: null
onbeforecopy: null
onbeforecut: null
onbeforepaste: null
onblur: null
onchange: null
onclick: null
oncontextmenu: null
oncopy: null
oncut: null
ondblclick: null
ondrag: null
ondragend: null
ondragenter: null
ondragleave: null
ondragover: null
ondragstart: null
ondrop: null
onerror: null
onfocus: null
oninput: null
oninvalid: null
onkeydown: null
onkeypress: null
onkeyup: null
onload: null
onmousedown: null
onmousemove: null
onmouseout: null
onmouseover: null
onmouseup: null
onmousewheel: null
onpaste: null
onreset: null
onscroll: null
onsearch: null
onselect: null
onselectstart: null
onsubmit: null
onwebkitfullscreenchange: null
onwebkitfullscreenerror: null
onwebkitspeechchange: null
outerHTML: "<input class="width-60" id="rs485addr" maxlength="3" type="textbox" value="1">"
outerText: ""
ownerDocument: HTMLDocument
parentElement: HTMLSpanElement
parentNode: HTMLSpanElement
pattern: ""
placeholder: ""
prefix: null
previousElementSibling: HTMLLabelElement
previousSibling: Text
readOnly: false
required: false
scrollHeight: 16
scrollLeft: 0
scrollTop: 0
scrollWidth: 60
selectionDirection: "forward"
selectionEnd: 3
selectionStart: 3
size: 20
spellcheck: true
src: ""
step: ""
style: CSSStyleDeclaration
tabIndex: 0
tagName: "INPUT"
textContent: ""
title: ""
translate: true
type: "text"
useMap: ""
validationMessage: ""
validity: ValidityState
value: "123"
valueAsDate: null
valueAsNumber: NaN
webkitGrammar: false
webkitRegionOverflow: "undefined"
webkitSpeech: false
webkitdirectory: false
webkitdropzone: ""
willValidate: true
Brian Tompsett - 汤莱恩
  • 5,753
  • 72
  • 57
  • 129
William Isted
  • 11,641
  • 4
  • 30
  • 45

6 Answers6

36

I'm not sure if it could be of any help, but when I had to deal with a similar situation in an event listener I used a setTimeout() with 1ms timeout where I put the main functionality checking for the value, etc.

That is because when the keydown event is fired the input field is not yet populated with the new data.

Simple jQuery example:

$('#input').on('keydown', function(e) {
  var field = $(this);
  var prevValue = field.val();
  setTimeout(function() {
    // check if new value is more or equal to 255
    if (field.val() >= 255) {
      // fill with previous value
      field.val(prevValue);
    }

  }, 1);
});

UPDATE

Use 'input' event in modern browsers.

var prevValue = 0;
$('#input').on('input', function(e) {
  var field = $(this);
  // check if new value is more or equal to 255
  if (field.val() >= 255) {
    // fill with previous value
    field.val(prevValue);
  } else {
    // If value is lower than 255 set it in prev value.
    prevValue = field.val();
  }
});
Kane Cohen
  • 1,790
  • 12
  • 17
13

You should not use keydown but keypress. Then you will receive the actual character code of the char to-be-typed.

See keypress, keydown, keyup value of input box AFTER event, http://www.quirksmode.org/dom/events/keys.html and especially http://www.quirksmode.org/js/keys.html.

inputElement.addEventListener("keypress", function(e) {
     var curval = e.srcElement.value;
     var newchar = String.fromCharCode(e.charCode || e.keyCode);
     if (/* condition */)
         e.preventDefault();
}, false);

If you just want to get the input value after something is typed, you need to use the keyup event.

Community
  • 1
  • 1
Bergi
  • 630,263
  • 148
  • 957
  • 1,375
  • I think the challenge is to construct the new value from curval and newchar. – Blago Sep 14 '12 at 21:52
  • Actually, it is curval and newkey - so yes, this is the challenge. – Bergi Sep 15 '12 at 11:05
  • 7
    keypress and keyup don't allow you to 'cancel' the key event. – Trevor Jul 01 '14 at 16:54
  • keypress also triggers if I hit backspace in Firefox. Which may not be what you want. – Pieter Sep 15 '16 at 13:30
  • 3
    Keypress is now a deprecated event: https://developer.mozilla.org/en-US/docs/Web/API/Element/keypress_event. The `input` event is a better alternative - https://caniuse.com/#feat=input-event – stwr667 May 31 '20 at 13:44
  • This does not answer the question. What is needed is the new value of the input as if we don't filter the input. – Odys Mar 20 '21 at 17:06
  • the keyup event is what you want for getting the latest value as you type into a field – eyal_katz Jul 23 '21 at 19:37
  • 2
    @eyal_katz or better just the `input` event, which works for any input method not just typing. – Bergi Jul 23 '21 at 21:53
1

Since this is litteraly the first result that comes up when searching for "how to get the new value on input keydown" im posting a working answer here.

This should be sufficient for a lot of cases, but i recommend checking if "keyup" or "input" or any other event is more fitting for your individual problem.

function getNewInputValue(e) {
      let newValue = e.target.value;
      let valueArray = newValue.split('');
      const selectionLength = (e.target.selectionEnd - e.target.selectionStart);
      if (e.key === 'Backspace') {
        if (selectionLength === 0 && e.target.selectionStart > 0) {
          valueArray.splice(e.target.selectionStart - 1, selectionLength + 1);
        } else {
          valueArray.splice(e.target.selectionStart, selectionLength);
        }
      } else if (e.key === 'Delete') {
        if (selectionLength === 0) {
          valueArray.splice(e.target.selectionStart, selectionLength + 1);
        } else {
          valueArray.splice(e.target.selectionStart, selectionLength);
        }
      } else {
        valueArray.splice(e.target.selectionStart, selectionLength, e.key);
      }
      newValue = valueArray.join('');
      return newValue;
}

if you use this snipped to prevent input if the new value does not fit your criteria you should also consider not checking when some "quality of life" features are triggered by the pressed key.

Im talking about navigating inside the input with the arrowkeys, or navigating to the next control by pressing tab and so on.

These are the keys i ignore:

const ignoredKeys = [
    'ArrowLeft',
    'ArrowRight',
    'Tab',
    'End',
    'Home',
    'ArrowUp',
    'ArrowDown',
  ];
  • This is the one solution that really solves the issue well. I don't see why it has no votes (other than age). I had the situation where the input had to have a certain checksum and I needed to reject any character that would violate the checksum, wherever in the string it was typed. Using timeout just seems too lame for modern use. – Octabode Jul 25 '22 at 16:51
0

The only thing I can come up with is that the srcElement Object that is outputted in the console is still linked to the event Object, even after the keydown Event so that the Object in the console is updated from 12 to 123 even when already in the console.

It doesn't happen with the direct output of event.srcElement.value because that is a literal value and is copied on logging, not referenced...

If you would be real fast you could check if you could see it change in the Console from 12 to 123 ;-)

Willem Mulder
  • 12,974
  • 3
  • 37
  • 62
0

Adding on @Bergi's comment here, so as to include text selections and caret position, you can do it as follows:

inputElement.addEventListener("keypress", (event) => {
    let curval = event.srcElement.value;
    let newchar = String.fromCharCode(event.charCode || event.keyCode);
    let curval_arr = curval.split("");
    curval_arr.splice(event.target.selectionStart, (event.target.selectionEnd - event.target.selectionStart), newchar);
    let newval = curval_arr.join("");

    //TODO: your logic here with "newval" containing the value to be.
    //console.log(curval, newchar, newval);
    //event.preventDefault();
}, false);
Martin
  • 474
  • 2
  • 6
  • 17
  • works ok except when the user hits backspace or delete, it adds a char when really it should be taking away. – Phil M Aug 20 '19 at 21:14
0

The simple solution: just use the keyup event (and not the keydown event). This will give you the latest value after the user typed the latest character. That resolves the issue.

eyal_katz
  • 1,111
  • 10
  • 17