Alternative for event's deprecated KeyboardEvent.which property - javascript

MDN states that KeyboardEvent.which is deprecated. How can I substitute it for a non-deprecated version?
For example, I have the following:
window.onkeydown = (event) => { console.log(event.which); }
I thought event.key.charCodeAt() could substitute event.which, but this won't work for keys such as ALT, CTRL or ENTER, and it only works if event.key.length === 1:
window.onkeydown = (event) => { console.log(event.key.charCodeAt()); }
To recap, event.which != event.code and event.which != event.key, therefore I am unable to simply use event.key.
Is there a substitute for event.which which detects combination keypresses including ALT, CTRL or ENTER?

TL;DR: These are the rules you should follow:
When getting text input from the user, use the keypress event along with e.key
For shortcuts and other combinations, the built-in way is to use keydown/keyup and check the various modifier keys. If you need to detect chords, you may need to build a state machine.
Background
Keyboard input is split into two phases - keydown/keyup pairs, which track physical keys being pressed, and composed characters that combines multiple sequences of keys to compute a character.
Getting "text"
If you want to know what the operating system thinks the composed sequence is, you should use KeyboardEvent.key
Sample code:
document.getElementById('a').addEventListener('keypress', e => console.log(e.key));
<input id="a" type="text" placeholder="type here">
The reason you want to do this most of the time is because many languages compose characters with several keypresses. The easiest for US-101 keyboards to understand is pressing the shift key + a is A, compared to just pressing a. For languages like Russian, with the altgr dead key, this becomes especially important.
The point I am trying to make is that doing all of this work yourself - detecting key sequences and determining the correct text output is a hard problem™. It is the job of the operating system for a reason.
Now, for older browsers, you may not want to use e.key for lack of older support. Then you can fall back to things like which, or other non-standard approaches.
At some point in the future, keypress may be removed by browsers. The beforeinput event is supposed to be the replacement. However, that event
is only supported in chrome, so I'm omitting in here for brevity's sake.
Getting keystrokes
Now then, suppose you are not tracking text, but rather key sequences. This is for things like games, or listening to ctrl-c etc. In this case, the correct thing to do is to listen to keydown/keyup events. For modifier keys, you can simply listen to the ctrlKey, shiftKey, and metaKey properties of the event. See below:
document.getElementById('a').addEventListener('keydown', (e) => {
const states = {
alt: e.altKey,
ctrl: e.ctrlKey,
meta: e.metaKey,
shift: e.shiftKey,
};
const key = e.key;
const code = e.code;
console.log(`keydown key: ${key}, code: ${code}`, states);
});
<input id="a" type="text" placeholder="press ctrl">
As an example, when pressing shift-o on my keyboard, I get the following:
keydown key: Shift, code: ShiftLeft {
"alt": false,
"ctrl": false,
"meta": false,
"shift": true
}
keydown key: O, code: KeyS {
"alt": false,
"ctrl": false,
"meta": false,
"shift": true
}
Hopefully the states part is pretty self-evident. They say whether that modifier key was pressed while the other key is down.
The difference between key and code has to do with keyboard layouts. I am using the software dvorak layout. Thus when I type the s key, the scan code that goes to the operating system says s, but then the OS converts that to o because it's dvorak. Code in this case always refers to the scan code (physical key being pressed), while the key corresponds to the operating system's best-effort to figure out what the "text" will be. This isn't always possible, especially with other languages. Again, this is why using the key for the keypress is the right way to go about it.
3rd party libraries
If this doesn't sound particularly easy, that's because it's not. The last time I was looking at this, I came across the mousetrap library, although I'm not sure I would recommend it, given some of the issues I found. It does, however, show an example of building a state machine to track key chords.
Addendum
This is also why you need to track keydown/keyup if you want to eat keystrokes. Since there is no "text" for ctrl+c, you won't get a proper keypress, and thus the browser will natively handle it. If you want to run your own behavior, you need to e.preventDefault() on the keydown itself. (Some of the followup events like copy can also be cancelled, but that's not universally true)
If you also just need to track keys inserted after-the-fact into an input field (or contenteditable div), see the input event.
History:
Updated 8/2019 to change keypress->beforeinput

As the other answers pointed out, event.which has one main problem: it does not return the same number for different browsers or computers (maybe this is why it is deprecated). Therefore, there is no perfect substitute for it, since it will output different numbers for different users.
So the main problem in trying to create a substitute for it (let's name it: function whichSubstitute(event)) is that the Meta and Shift keys, for example, don't have a unique number that whichSubstitute should get when one of them is pressed, it varies according to OS.
With that in mind, there are two approaches for getting the unicode code point for the user's input.
Getting the unicode value for the character that the user inputted (e.g., ü, which would be 'ü'.codePointAt(0)).
Getting a numeric value for the character that corresponds to the physical key pressed in the keyboard, which might be different from what was inputted to the text field. As AnilRedShift mentioned, the keyboard layout might change the "natural" output from that key in the keyboard, in such a way that the key s might output o. In this case, we'd get 's'.codePointAt(0), instead of getting the value for 'o' (that is, what was actually outputted), like we would get using the first approach. More on this from MDN:
For example, the code returned is "KeyQ" is for the "q" key on a QWERTY layout keyboard, but the same code value also represents the "'" key on Dvorak keyboards and the "a" key on AZERTY keyboards. That makes it impossible to use the value of code to determine name of the key is to users if they're not using an anticipated keyboard layout.
In short: approach number 1 gets the unicode code point for ü, whereas approach number 2 gets the code points for SHIFT, 6 and U (since SHIFT+6+U == ü).
In this answer, we'll use String.prototype.codePointAt() instead of String.prototype.charCodeAt(). The differences are well explained here. The reason is that we can get the whole unicode number with .codePointAt(0), whereas the .charCodeAt(0) would lack .codePointAt(1) to complete the UTF-16 encoded code point.
For approach number 1, we can use the following code:
function whichSubstitute(event) {
const theKey = event.key;
if (theKey.length === 1) {
return theKey.codePointAt(0);
}
switch (theKey) {
case "Backspace":
return 8;
case "Tab":
return 9;
case "Enter":
return 13;
case "Alt":
return 18;
case "Escape":
return 27;
case "Delete":
return 127;
case "Dead": //As of july 2018, Firefox has no support for "Dead" keys https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key
{}
break;
case "Unidentified":
alert("handle the 'Unidentified' if you want to!");
}
/*** there are many other possible key values https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values
but, AFAIK, there are no unicode code points for them, such as:
switch (theKey) {
case "AltGraph":
case "CapsLock":
case "Control":
case "Fn":
case "FnLock":
...
event.which may output some number for them, but it is not consistent across
browsers/machines and they may overlap with other code points. For example:
case "ArrowUp":
return 38; //this overlaps with "&"
case "ArrowLeft":
return 37; //this overlaps with "%"
case "ArrowDown":
return 40; //this overlaps with "("
case "ArrowRight":
return 39; //this overlaps with "'"
***/
return 0;
}
//test
document.onkeydown = (event) => {
console.log('whichSubstitute: ' + whichSubstitute(event) + '; event.which: ' + event.which);
//note that whichSubstitute gets the ASCII number of 'a', while event.which only gets the ASCII number of 'A' (upper case, always)
}
This, of course, does not solve the problem of getting only one unique consistent number for a pressed key when there is no unicode code point for it (as in the case of Meta). Such keys need to be handled by the programmer according to her/his needs.
For approach number 2, we can use the following code:
function whichSubstitute(event) {
const theChar = event.code;
if (theChar.startsWith('Key')) {
return theChar.codePointAt(3);
}
if (theChar.startsWith('Digit')) {
return theChar.codePointAt(5);
}
switch (theChar) {
case "Backspace":
return 8;
case "Tab":
return 9;
case "Enter":
return 13;
case "Alt":
return 18;
case "Escape":
return 27;
case "Delete":
return 127;
case "Minus":
return 45;
case "Plus":
return 43;
case "Equal":
return 61;
case "Delete":
return 127;
case "BracketRight":
return 93;
case "BracketLeft":
return 91;
case "Backslash":
return 92;
case "Slash":
return 47;
case "Semicolon":
return 59;
case "Colon":
return 58;
case "Comma":
return 44;
case "Period":
return 46;
case "Space":
return 32;
case "Quote":
return 34;
case "Backquote":
return 39;
//there are also "Numpad....." variants
case "Unidentified":
alert("handle the 'Unidentified' if you want to!");
}
/*** there are many other possible character values https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/code
but, AFAIK, there are no unicode code points for them, such as:
switch (theKey) {
case "AltLeft":
case "CapsLock":
case "ControlRight":
case "Fn":
case "NumpadDecimal":
...
event.which may output some number for them, but it is not consistent across
browsers/machines and they may overlap with other code points.
***/
return 0;
}
//test
document.onkeydown = (event) => {
console.log('whichSubstitute: ' + whichSubstitute(event) + '; event.which: ' + event.which);
}
This second approach might be useless, since the same physical key might output different unicode characters according to different keyboard layouts. The users might have no idea of which key they should press.
Related: https://www.w3.org/TR/uievents/#keys

From the specification:
which of type unsigned long, readonly
which holds a system- and implementation-dependent numerical code signifying the unmodified identifier associated with the key pressed. In most cases, the value is identical to keyCode
keyCode of type unsigned long, readonly
keyCode holds a system- and implementation-dependent numerical code signifying the unmodified identifier associated with the key pressed. Unlike the KeyboardEvent.key attribute, the set of possible values are not normatively defined in this specification. Typically, these value of the keyCode should represent the decimal codepoint in ASCII [RFC20][US-ASCII] or Windows 1252 [WIN1252], but may be drawn from a different appropriate character set. Implementations that are unable to identify a key use the key value '0'.
See Legacy key models for more details on how to determine the values for keyCode.
(I have omitted the links)
So it is quite easy to create a version that is compatible with the specification. The easiest version just returns 0 for each key.
A slightly more involved version takes event.key and grabs it's ASCII number. You can do the same for the control keys (altKey, ctrlKey, shiftKey).
In short, as it stands the behavior of which is different between systems and browsers. Using the non-deprecated event information you can create a more robust version that removes these differences and will be more future proof.
You can check the behavior of your version with the implementation of which in major browsers. If you are not using any edge cases your version will be both simple and compatible.

Related

Allow only alphanumeric, special letters and symbols in input

I need to allow user to enter English and French characters (so I need to take in consideration chars like é,à,ç,è...etc). I also need to allow user to enter symbols and numbers.
In other words I need to prevent the user from entering non latin characters like arabic, chinese, japanese, russian ...etc
$("input:text,textarea").keydown(function(event) {
var allowed = /[A-Za-z0-9àâçéèêëîïôûùüÿñæœ!##\$%\^&\*\(\)_|}{~">:<\?/\]\[\\=\- ; ]/g;
var key = String.fromCharCode(event.which);
if (event.keyCode == 8 || event.keyCode == 37 || event.keyCode == 39 || allowed.test(key)) {
return true;
} else {
return event.preventDefault()
}
});
This works well except for some characters like ; ? / Ù even though I aded them
There's a couple of issues with the pattern you've showed. For a start, you don't have to escape all the metacharacters inside [] definition, but only those that might lead to its incorrect parsing. So quite a bit of those \ are redundant.
Also, be aware that patterns designed just for .test purposes should in general avoid /g flag, as this leads to some surprising results:
const patt = /[ab]/g;
console.log( patt.test('a') ); // true
console.log( patt.test('b') ); // false
Finally, as you didn't make your pattern case-insensitive, all the capital letters with diacritics will be missed by that. You can fix this by adding /i flag, which should work in your case, though, but... that's not the true reason your code fails.
See, the far bigger problem than all the previous combined is using event.which in combination with keydown event. Again, there are some minor issues with the approach overall (for example, how can you prevent user from pasting incorrect values inside the form - with or without a mouse?), but the particular thing that bites you is inconsistency of event.which results:
The which read-only property of the KeyboardEvent interface returns
the numeric keyCode of the key pressed, or the character code
(charCode) for an alphanumeric key pressed.
Simply said, String.fromCharCode() line works fine only for Latin characters and digits keys on the keyboard - but not for all the rest of the symbols you want to allow in the input:
// `0` pressed:
event.which - 48
String.fromCharCode - '0'
// '-' (neighbor of 0) pressed:
event.which - 189
String.fromCharCode - '½'
Now I suppose the real question is 'well, how to avoid this?'. One possible approach is checking event key property instead, which is now universally supported:
The KeyboardEvent interface's key read-only property returns the value
of the key pressed by the user, taking into consideration the state of
modifier keys such as Shift as well as the keyboard locale and layout.
In this case, however, you still need to handle copy-paste too, as well as some edge cases on keyboard input itself.
What I'd suggest as alternative is using input event to test the whole value of the input after the change, and not just individual letters. While input event is not cancellable, it's possible to revert the change it introduces, like this:
document.querySelector('input').oninput = (function() {
let oldValue = '';
const smallEl = document.querySelector('small');
const notAllowed = /[^a-zàâçéèêëîïôûùüÿñæœ0-9 \\?!##$%^&*":;~=|\-(){}<>[\]]/i;
return function(event) {
const val = event.target.value;
if (notAllowed.test(val)) {
event.target.value = oldValue;
smallEl.removeAttribute('hidden');
}
else {
oldValue = event.target.value;
smallEl.setAttribute('hidden', '');
}
}
})();
small {
color: red;
}
[hidden] {
display: none !important;
}
<label>Let's put some text here: <input /><br />
<small hidden>Non-Latin alpha characters are not allowed</small></label>
This works, but has two caveats. First, the validator now has to store the previous value of input (which raises its complexity a bit). Second, when incorrect chars are thrown into a mix and the value of input is rewritten, cursor always jumps into the end of the line. Not great, but definitely not terrible to me.
All of this won't be necessary when beforeinput event will be properly implemented in all the browsers. At this moment (Nov 2020) Firefox has it hidden under experimental flag (here's the ticket), and Chrome seems to not handle its cancellation correctly:
document.querySelector('input').addEventListener('beforeinput', (function() {
const smallEl = document.querySelector('small');
const notAllowed = /[^a-zàâçéèêëîïôûùüÿñæœ0-9 \\?!##$%^&*":;~=|\-(){}<>[\]]/i;
return function(event) {
const val = event.target.value;
if (notAllowed.test(val)) {
event.preventDefault();
smallEl.removeAttribute('hidden');
}
else {
smallEl.setAttribute('hidden', '');
}
}
})());
small {
color: red;
}
[hidden] {
display: none !important;
}
<label>Let's put some text here: <input /><br />
<small hidden>Non-Latin alpha characters are not allowed</small></label>
When I test it locally in Chrome 87, the input gets stuck immediately after processing the first 'incorrect' character, disallowing any further action on that input. There are other issues with beforeinput in Chrome, some of them stay opened for ~2 years already, so I wouldn't place my bets on this event's usability in the nearest future.
As a final sidenote, one should strongly consider checking this UX Experience thread to validate the whole approach from UX perspective. While Prevention is the only way in some cases, in others it might just lead to user frustration ("why doesn't this stupid app let me put my proper name in it???" is the typical reaction), so choose your options wisely.
I've seen that you're currently using jquery and the answer given was using pure Js, so here's a solution using Jquery:
$("input:text,textarea").on("input",function(event) {
const notAllowed = /[^a-zàâçéèêëîïôûùüÿñæœ0-9 \\?!##$%^&*":;~=|\-(){}<>[\]]/i;
return (function(event){
const val = event.target.value;
if(notAllowed.test(val)){
//Show error message
// Your code here ...
// Getting old value
let old = $(this).data('val')? $(this).data('val'):'';
event.target.value=old
}
else{
//Remove error message
// Your code here ...
//Setting current value in order to use in case a non permitted character is entered
$(this).data('val',event.target.value);
}
})(event)
});
you can then implement an error message
Filtering keypresses can work to eliminate the characters you don't want to allow, although you'll also need to handle copy/paste too.
Filter on Unicode character ranges is the most concise method I think. Pick the ranges / chars you want to allow from here: https://en.wikipedia.org/wiki/Latin_script_in_Unicode
// Allow backspace, left and right arrows
if ([8, 37, 39].includes(event.keyCode)) {
return true;
}
// Check for disallowed characters
const re = /[^\u0020-\u00ff\u0152\u0153]/;
var key = String.fromCharCode(event.which);
if (!re.test(stringValue)) {
return true
}

Is there a way to retrieve the displayed value of a pressed key in keyboard event

I would like to let the user press a combination of keys and display the input in a readable way.
If the the pressed for example altP I would like to display alt P.
I know how to handle the modifier keys themselves but I couldn't find a solution for the "normal" keys. I tried to use the event.code property which gives me in this case KeyP (The event.key or event.which properties are not suitable as the modifier keys would change the value to eg π).
But I would have to map the value of event.code to P, especially for keys with special characters as they might have very different values on different layouts.
Is there a property to retrieve the displayed value of a key (the value printed on the physical keyboard without modifiers!) or a library to map the event.code to the displayed value for the most common keyboard layouts?
(Eg event.code = "Quote" mapped to Quote/" for American layout and to Ä for German layout)
window.onload = function () {
document.addEventListener("keydown", function(){
document.getElementById("keydownResult").innerText = event.code + " pressed. Value is " + event.key + ".";
// Procduces "KeyP pressed. Value is π." on macOS with german layout.
});
};
<p id="keydownResult"></p>

Detecting enter key pressed

Are there any ways available in jquery to detect whether Enter key has pressed?
I know that we can use keycodes/charset to identify the Enter key press, but I do not need to hard code an integer value in my js script as it will become a magical number. I need to know whether there are any other possible ways to detect Enter key press, which is something like e.shiftKey for detecting shift key press using event object.
Thanks.
So, you want to detect the Enter key being pressed without hardcoding a 13 for the keycode.
Now, I could suggest using 6.5*2 as the keycode, then, but that'd be silly.
The real answer is that there is no built-in constant for the Enter key, like the Shift key has.
The reason Shift has it, is because that key is often pressed in combination with other keys. You can't detect a Shift keyDown event when pressing Shift+A, for example, because the event for the modifier has passed already when you're handling the keyDown event for the A.
Frankly, your only real option would be to hardcode a application-wide constant that says something along the lines of:
window.keyCodes = {
Enter: 13,
SomeKey: 99
}
Then you can check against it like this:
if(e.keyCode === keyCodes.Enter)
Or, it may be possible to write a function that compares the character of the entered key with a string that contains only a return, but then you'd just be hardcoding a return, any way.
The keycode for the enter key is : 13
if(e.keyCode == 13)
//do something...
This is the immediate way that people detect this particular event, but there are other ways to identify the number 13.
var DOM_VK_RETURN = 13;
$(document).on('keydown', function(e) {
var code = e.keyCode || e.which;
if(code == DOM_VK_RETURN) {
console.log("Enter key pressed");
}
});
However, if you do not want to use an integer to detect the key, we could use hexadecimal.
http://jsfiddle.net/hk2eL/3/

A javascript regex to allow only Latin characters and other helpful keys

For an HTML input value, is it possible to define with JavaScript a regular expression that accepts only Latin characters (any case) and all other keys like backspace, delete, arrow keys, and also .dot, #at?
Is it for event key evaluation, not afterwards, that's why I need the arrow and the other keys.
You can use something like:
JavaScript
document.getElementById('foo').onkeydown = function (e) {
if (e.keyCode < 65 || e.keyCode > 90) {
e.preventDefault();
return false;
}
};
HTML
<textarea id="foo"></textarea>
This will limit you to enter only small letters. It should be a little modified to work also with uppers.
JSfiddle.
Unless you give more details, I think regex will not help you.
I don't know details of the key event you need to use, but I wrote myself a object like a dictionary, worked well in one of my projects, but of course its not fail proof, and it's very hard to be 100%, because of many keyboard layout and languages out there, and the unstandadized event handling in javascript and browsers implementations. I suggest reading first this article it helped me a lot http://unixpapa.com/js/key.html
My workaround for en-US english keyboards.
var Keys = { "BACKSPACE":8, "TAB":9,"ENTER":13,"SHIFT":16,"CTRL":17,"ALT":18, "PAUSEBREAK":19, "CAPSLOCK":20,"ESC":27, "SPACE":32, "PAGEUP":33, "PAGEDOWN":34, "END":35, "HOME":36, "LEFT":37, "UP":38, "RIGHT":39, "DOWN":40, "PRNTSCRN":44, "INSERT":45, "DELETE":46, "0":48, "1":49, "2":50, "3":51, "4":52, "5":53, "6":54, "7":55, "8":56, "9":57, "A":65, "B":66, "C":67, "D":68, "E":69, "F":70, "G":71, "H":72, "I":73, "J":74, "K":75, "L":76, "M":77, "N":78, "O":79, "P":80, "Q":81, "R":82, "S":83, "T":84, "U":85, "V":86, "W":87, "X":88, "Y":89, "Z":90, "WINKEY":91, "WINKEYR":92, "APPLICATION":93, "NUM0":96, "NUM1":97, "NUM2":98, "NUM3":99, "NUM4":100, "NUM5":101, "NUM6":102, "NUM7":103, "NUM8":104, "NUM9":105, "MULTIPLY":106, "ADD":107, "SUBTRACT":109, "DECIMALPOINT":110, "DIVIDE":111, "F1":112, "F2":113, "F3":114, "f4":115, "F5":116, "F6":117, "F7":118, "F8":119, "F9":120, "F10":121, "F11":122, "F12":123, "NUMLOCK":144, "SCROLLLOCK":145, "SEMICOLON":186, "EQUAL":187, "COMMA":188, "DASH":189, "PERIOD":190, "SLASH":191, "GRAVE":192, "OPENBRAKET":219, "BACKSLASH":220, "CLOSEBRAKET":221, "SINGLEQUOTE":222, "MMNEXT":176, "MMPREVIOUS":177, "MMSTOP":178, "MMPLAY":179, "MMREWIND":227, "MMFORWARD":228, "MYCOMPUTER":182, "MYCALCULATOR":183, "HELP":225, "Invalid!":0
}
you can use like
if(event.keyCode == Keys['RIGHT']) //go right
if(event.keyCode == Keys['LEFT']) //go left
if(event.keyCode == Keys['ENTER']) //do something
if(event.keyCode == Keys['ESC'] || event.keyCode == Keys['BACKSPACE']) //exit
You mentioned arrows and other keys, if you're using keys to bind something like a game, avoid using modifiers like CTRL ALT WINKEY ALTGR APPLICATION OPTION COMMAND they are a mess, there are so many inconsistencies, like Command key pretending to be Application key, the right alt as another control, etc, also some keyboards doesn't have a second alt, or ctrl. So its a hell of exceptions.

javascript (jquery) numeric input: keyCode for '3' and '#' are the same

I need to set up an <input type="text" /> so that it will accept only numeric chars, backspace, delete, enter, tabs and arrows.
There's a lot of exemple around there, i started with something similar to this:
function isNumericKeyCode (keyCode){
return ( (keyCode >= 48 && keyCode <= 57) //standard keyboard
||(keyCode >= 96 && keyCode <= 105)) //Numpad
}
$('#myTextBox').keydown(function(e){
var handled = true;
var keyCode = e.keyCode;
switch(keyCode){
//Enter and arrows
case 13:
case 37:
case 38:
case 39:
case 40:
doSomethingSpecialsWithThesesKeys();
break;
default:
handled = false;
break;
}
if ( !handled
&& keyCode !== 8 //backspace
&& keyCode !== 9 //tab
&& keyCode !== 46 //del
&& !isNumericKeyCode(keyCode)){
handled = true;
}
return handled;
});
All that worked perfectly until I hit the "#" key. In my french canadian keyboard, the "#" has his own key (no shift implied) that returns keyCode 51, the same as the number "3".
I think that in US keyboard, the "#" is obtained by pressing shift+3, that may be why they have the same keycode.
Now I realize that I have to handle the shift and alt keys too, but that's another story.
It works differently with the jquery keypress event, which offer the charCode property, but I did not used it at first because of what the documentation says :
as the keypress event isn't covered by any official specification, the
actual behavior encountered when using it may differ across browsers,
browser versions, and platforms.
Also, I would need a workaround in that case to handle tabs, arrows and other special keys since they don't provide a charCode.
So the question is :
is there a way to allow only some specifics chars using the keydown event? And that, in a way that will work independently of the keyboard layout?
As a side quest : Which browsers may be problematics with the keypress event? I mean, currently I don't really care if my website does not support IE6. I am targetting recent browsers.
Edit
As someone pointed out in the comments, this method does not allow user to "ctrl+v" a number in the input. In my particular case this is really not a requirement to be able to paste a number. But this popped something in my head, the user still can right-clic > copy some text in the input, and in that case that could be anything. The more I think of it, the more it seems to me that I will need the keydown event to handle tabs and arrows, and another event to handle the input itself.
Edit2
A lot of beautiful answers here, but the award goes to mrtsherman for the use of input and propertychange events. I will use a combination of this answer for the numeric validation, plus the keyCode event as before for the special use of arrows, tabs and enter keys.
How about something like this. This should cover cut/paste and also rmb content. We monitor the textbox for any change in content. Then we use a regex to filter out characters based on a whitelist. This won't handle non-character key, but I think that is okay.
The \d flag says that only digits should be accepted.
http://jsfiddle.net/UXeva/1
$('#myTextBox').bind('input propertychange', function() {
var text = $(this).val();
if (isNaN(text)) {
$(this).val(text.replace(/[^\d]/gi, ''));
}
});
We bind to two events here. input for FireFox and propertychange for other browsers.
If older browsers are'nt an issue, the number input type should cover this.
<input type="number" />
If not you could use the isNaN javascript function
$("#number1").on('keyup', function() {
var myval = $(this).val();
if (isNaN(myval)) {
alert('numbers only!');
}
});
Personally I would do some regex filtering with a check to see if the value has changed, that will allow any character that does not change the value, like tabs, enter and arrows. With a regex you could also add or remove any character, or you could use \d for digits only or as below, [0-9]. Up to you really what your exact needs are?
var P;
$("#number2").on('keyup', function() {
var V = $(this).val();
if (V != P) {
$(this).val(V.replace(/[^0-9]/g,''));
}
P=V;
});
They could also be combined to something like this:
$("#number3").on('keyup', function() {
var V = $(this).val();
if (isNaN(V)) {
$(this).val(V.replace(/[^0-9]/g,''));
}
});
Here's a FIDDLE to test them out!
Why not do something like this? It uses a combination of the keyup() event and isNaN(). It'll work whether the user types with the keyboard or pastes a number.
The way it works is, as soon as the text changes, it will check if the value is a number. If not, it will trim the input until it is a number. So, if you enter 25s or 25ss, you will be left with 25.
This will work with ctrl+v paste as well. It won't work with right-click paste and for that reason, I have disabled right-clicking only on the textbox.
Live Demo
The Jquery
$(document).ready(function(){
$('#number').keyup(function(){
var input = this.value;
while (isNaN(input))
{
input = input.substring(0,input.length-1);
$('#number').val(input);
}
});
$('#number').bind("contextmenu",function(e){
return false;
});
});
jQuery also provides a shiftkey boolean on the event object:
$('#myTextBox').keydown(function(e){
if(e.keyCode === 51 && !e.shiftKey){
// '3' key pressed while shift was **not** held down (not '#')
}
});
EDIT I reread your question and changed the code above for !shiftkey

Categories