Allow only alphanumeric, special letters and symbols in input - javascript

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
}

Related

Alternative for event's deprecated KeyboardEvent.which property

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.

Want to write code for vehicle registration number which doesnot allow special characters and whitespaes on each keypress

I want to write a code for not allowing to take special character or whitespace as input.
eg:- TN03UB8192
this is the required input. If i input as: TN03U* it woun=ld not take * as input. Instead of taking it as input need to halt or take next allowed character as input.
Now i have a code
this is working but will show alert only after 10 key press.
Please help me
function alphanumeric(inputtxt)
{
var letters = /[A-Z]{2}[0-9]{2}[A-Z]{2}[0-9]{4}$/;
if(inputtxt.value.match(letters))
{
alert('Your registration number have accepted : you can try another');
document.form1.text1.focus();
return true;
}
else
{
alert('Please input in correct format');
return false;
}
}
You'll definitely want to have both client side and server-side checking for this. You want it on the client side just to avoid the hassle of submitting the form and then it coming back saying the input is wrong.
Here is a link to a question that was asking a similar thing. Be sure to read all the answers, because there are fringe cases, like pasting, where you want to apply the filter as well, not just with individual keypress checks.
Stealing one of the non-accepted answers, because its better than the accepted one for our purposes.
var text = document.getElementById('text');
text.onkeypress = text.onpaste = checkInput;
function checkInput(e) {
var e = e || event;
var char = e.type == 'keypress'
? String.fromCharCode(e.keyCode || e.which)
: (e.clipboardData || window.clipboardData).getData('Text');
if (/[^\d]/gi.test(char)) {
return false;
}
}
If the event is a keypress, var char will become the letter of the key they pressed.
if the event is not a keypress, then it must be a paste, so char = clipboard data.
next, we run the regex check to see if the data passes. if not, we return false (don't let that new text be entered into the input box). If it does pass, don't do anything, just let the input act as it normally would, accepting the valid thing you just entered into it.

RegEx ignoring string values in encased in (brackets); and removing mark when input box is cleared

I need your help,
The following JavaScript code below works to find a given match in the UL LI list and compares it to that of the input box. My question is two fold though, while it works, it seems to ignore any values that are encased by any brackets and;
The code seems to leave the search results (matches) still highlighted, even if the input box is cleared. The mark tags should be removed if the user is not searching for anything.
How can the code be modified so as to accommodate the two above conditions?
Here is a fiddle: http://jsfiddle.net/z4TMC/4/
The code in question:
$("#refdocs").keyup(function(){
var search = $(this).val();
$("#refdocs_list li").each(function(){
var val = $(this).text();
if (val.toLowerCase().indexOf(search) >= 0 && search.length) {
//$(this).addClass("selected");
$(this).html(val.replace(RegExp("("+search.replace(/[\-$*{}()]/g,"\\$1")+")","ig"), "<mark>$1</mark>" ));
}
else {
$(this).removeClass("selected");
}
});
});
Your regex isn't perfect just yet. You aren't replacing/escaping sqare brackets ([]), nor are you properly escaping any backslashes that might have been entered. I've set up this working fiddle
All I had to do to get it working was add a listener to handle mouse input events, and change the regex a tad:
//add this, change triggers when focus is lost, though, but handles empty fields
$("#refdocs").on('change', function()
{
if (this.value == '')
$("#refdocs_list li").each(function()
{
this.innerHTML = $(this).text();
});
else
$(this).trigger('keyup');//run keyup handler if required
});
I've also noticed that, for one of the list items (XAF-2014-123456), your code fails to match XAF if the user input is in upper-case. That's because of your if condition:
if (val.toLowerCase().indexOf(search) >= 0 && search.length)
{//val.toLowerCase() -> also lowerCase the user input to ensure same case!
I've simply changed it to:
if (val.toLowerCase().indexOf(search.toLowerCase()) >= 0 && search.length)
{//lower-case to lower-case comparison, XAF and xaf both work now.
And now for the regex:
search.replace(/[-\\$*{}()[]]/g,"\\$1")
Notice how I moved the - to the front of the character-class. That's simply so that it doesn't need escaping.
Next, to filter out any backslashes that might have been put in by the user, I match a \\ (an escaped backslash matches a literal \).
The rest of the character class is pretty much the same, but right near the end (the closing ]), I've also added [], to match square brackets. Normally, you'd escape them, but in this case, there is no ambiguity. Compare this:
/ambi[a-z[]0-9]/g
Here, there are a number of ways to interpret the regex: a char class of a-z+ 0-9 and [] literals, or a malformed pattern, with a character class of a-z[, a digit and a trailing ]... However, [{}[]] is clearly a char-class that matches either curly or square brackets. If you want to play it safe, though, adding backslashes doesn't make any difference:
/[-\\$*{}()\[\]]/g
Update
Though this isn't something you were looking for: you commented you wanted to support IE10. IE has, since IE9, slowly but surely been conforming more and more to the standard, upheld by other browsers. Therefore, it's perfectly do-ably and pretty easy to write your code in a X-browser compatible way whilst maintaining X-browser compatibility.
It's not a big secret that I don't really like jQ (I find it bulky, slow and used way more than it should). So I've gone ahead and put together this fiddle, which shows you a VanillaJS approach of what you're trying to do. It's still a tad rough around the edges, but you should be able to get this up and running in no time.
In this code, I've used "clever" (as in efficient) techniques such as a closure/IFFE (to store the DOM references, avoiding too many DOM lookups), and event delegation. Google these terms and work out how this code ticks. If you want to, that is. I promise you though: it's worth it, you'll find that most of the jQ code out there is quite ghastly.
Anyway, for those of you that care: here's the code:
(function(refdoc)
{
var listItems = document.querySelectorAll('#refdocs_list li'),
wrapper = document.querySelector('#refdocs_list'),
classPattern = /\bselected/,
callback = function(e)
{
var i;
for (i=0;i<listItems.length;++i)
listItems[i].innerHTML = listItems[i].textContent;
if (!this.value)
return e;
for (i=0;i<listItems.length;++i)
if (listItems[i].textContent.toLowerCase().indexOf(this.value.toLowerCase()) >= 0)
listItems[i].innerHTML = listItems[i].textContent.replace(new RegExp("("+this.value.replace(/[-\\$*{}()[]]/g,"\\$1")+")","ig"), "<mark>$1</mark>" );
};
wrapper.addEventListener('click', function(e)
{
var i, t = (e = e || window.event).target || e.srcElement;
if (t.tagName.toLowerCase() === 'li')
{
for (i=0;i<listItems.length;++i)
{
listItems[i].innerHTML = listItems[i].textContent;
listItems[i].className = listItems[i].className.replace(classPattern, '');
}
t.className += ' selected';
refdoc.value = t.textContent;
}
}, false);
refdoc.addEventListener('keyup', callback, false);
refdoc.addEventListener('change', callback, false);
}(document.querySelector('#refdocs')));
All you need to do is put this in a window.addEventListener('load', function(){ /*code here */}, false); callback, and that's it.

Check if INSERT mode is ON when typing in an input

I'm trying to calculate the value of an input field on various events regardless of the event caught.
I'm taking into account the events keypress keyup keydown cut paste events (Do I forget anything?).
I'm trying to determine if the text-input INSERT mode is on (default - on), or off. I cannot determine the mode by capturing a key event of that key, though I don't know what was the initial state.
Does anyone know a way? Preferably - a cross browser solution that includes IE8+, Chrome and Firefox.
Any solution, or in the words of Barney Stinson, "scam, con, hustle, hoodwink, gambit, flim flam, stratagem, and bamboozle" that could help me would be appreciated.
For IE only:
document.queryCommandValue("OverWrite");
As far as I know, Firefox and Chrome don't have overwrite mode. The insert key doesn't work in those browsers, and they are always in insert mode.
Moreover, Mac keyboard doesn't have a insert key from the beginning. So Safari also is always in insert mode.
Although I don't think you can directly access the state of the user's Insert status, you can figure out how long the strings are when the user is editing the field.
Consider this, tied with a simple <input id="input" />:
var i = document.getElementById('input');
document.onkeydown = function(e) {
var c = String.fromCharCode(event.keyCode);
if(null !== c.match(/\w/)) {
l = i.value.length;
}
}
document.onkeyup = function(e) {
var c = String.fromCharCode(event.keyCode);
if(null !== c.match(/\w/)) {
if(l === i.value.length) {
console.log("Keyboard insert might be off - length hasn't changed");
}
}
}
Note that there is a rudimentary check to try and isolate only letters and numbers (with the match against the keyCode (borrowed from here), as you don't want to perform the check against a shift key being pressed, for instance.
Basic POC here: http://jsfiddle.net/Xp3Jh/
I'm certain there are more in-depth checks you can do, but hopefully this helps!

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