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
Related
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
}
I have an input on one of my pages that has listeners on it that perform formatting on values entered into it.
The field only allows certain input(numerical as well as certain other characters), which is controlled with a keypress and a keyup listener. The keypress prevents illegal input, and the keyup performs formatting(and also checks input, in case the user pasted something into the field instead of typing).
It worked fine in Chrome and IE (back to IE8, I don't care about anything earlier), but in Firefox I was unable to use the tab key, arrow keys, backspace, and was unable to copy or paste using ctrl+c/v
After some investigation I found that the problem lies with this listener:
$(this).keypress(function(e)
{
consumeIllegalFloatKeyPress(e);
});
In IE and Chrome, keys like tab, arrows and backspace weren't even triggering the listener, and keypresses like v and c would not trigger it either, when used with the ctrl key. However, in FF it picks up all the keypresses, which resulted in
consumeIllegalFloatKeyPress(e);
getting called, and finding that the keypresses were illegal.
The fix was easy enough - I have an array of legal inputs that is used to check what should be allowed, so I just added the charCodes for v and c, and put in a key for the ctrlKey as well.
What I am confused about is why these are being handled differently in different browsers? I thought that, since it was all javascript, that it would handle the CTRL key the same across all browsers.
If anyone has any information on this, or knows of somewhere I can read up more on it, I'd be very interested and grateful!
Try the below solution. This works perfect for my issue
function captureKeyPress(e) {
var keycode = (e.keyCode ? e.keyCode : e.which);
var ctrlKeyPressed = e.ctrlKey;
var key = e.which;
switch(e.key){
case "c": //right arrow key
if (!ctrlKeyPressed) {
alert('C pressed');
}
break;
}
}
window.addEventListener("keypress", captureKeyPress);
Let's have a look at official documentation:
jQuery keypress listener
2 important things can be read here:
Note: 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.
And:
This method is a shortcut for .on( "keypress", handler ) in the first two variations, and .trigger( "keypress" ) in the third.
Let's have a look at what the Javascript documentation says about keypress:
javascript keypress event
After a few clicks we see a nice table on this page
The table shows which browsers accepts certain keys, like non-printable keys (arrow keys, control, page down, ...) and which don't.
The final answer to your question is: if there is no set standard for something (like the keypress event), then browsers will do whatever they feel like doing. For Google chrome this means it allows CTRL + V, where Mozilla Firefox filters it.
Please try this solution:
$(document).on("keypress", this, function (e) {
var keycode = (e.keyCode ? e.keyCode : e.which);
/* Example */
if (keycode === 27) {
alert("Escape key");
}
});
...and you can enable or disable keys what you whant.
I will give you one my function for this:
FUNCTION:
$.fn.pKey = function (key, callback) {
var key=key;
return this.each(function () {
$(document).on("keypress", this, function (e) {
var keycode = (e.keyCode ? e.keyCode : e.which);
if (keycode === key) {
callback.call(this, e);
};
});
});
};
EXAMPLE:
$("#my-div").pKey(17,function (e) {
/* disable CTRL*/
e.preventDefault();
})
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/
I have a function that is triggered by the onkeydown event of a textbox. How can I tell if the user has hit either the backspace key or the del key?
Try this:
document.addEventListener("keydown", KeyCheck); //or however you are calling your method
function KeyCheck(event)
{
var KeyID = event.keyCode;
switch(KeyID)
{
case 8:
alert("backspace");
break;
case 46:
alert("delete");
break;
default:
break;
}
}
event.key === "Backspace" or "Delete"
More recent and much cleaner: use event.key. No more arbitrary number codes!
input.addEventListener('keydown', function(event) {
const key = event.key; // const {key} = event; ES6+
if (key === "Backspace" || key === "Delete") {
return false;
}
});
Mozilla Docs
Supported Browsers
Nowadays, code to do this should look something like:
document.getElementById('foo').addEventListener('keydown', function (event) {
if (event.keyCode == 8) {
console.log('BACKSPACE was pressed');
// Call event.preventDefault() to stop the character before the cursor
// from being deleted. Remove this line if you don't want to do that.
event.preventDefault();
}
if (event.keyCode == 46) {
console.log('DELETE was pressed');
// Call event.preventDefault() to stop the character after the cursor
// from being deleted. Remove this line if you don't want to do that.
event.preventDefault();
}
});
although in the future, once they are broadly supported in browsers, you may want to use the .key or .code attributes of the KeyboardEvent instead of the deprecated .keyCode.
Details worth knowing:
Calling event.preventDefault() in the handler of a keydown event will prevent the default effects of the keypress. When pressing a character, this stops it from being typed into the active text field. When pressing backspace or delete in a text field, it prevents a character from being deleted. When pressing backspace without an active text field, in a browser like Chrome where backspace takes you back to the previous page, it prevents that behaviour (as long as you catch the event by adding your event listener to document instead of a text field).
Documentation on how the value of the keyCode attribute is determined can be found in section B.2.1 How to determine keyCode for keydown and keyup events in the W3's UI Events Specification. In particular, the codes for Backspace and Delete are listed in B.2.3 Fixed virtual key codes.
There is an effort underway to deprecate the .keyCode attribute in favour of .key and .code. The W3 describe the .keyCode property as "legacy", and MDN as "deprecated".
One benefit of the change to .key and .code is having more powerful and programmer-friendly handling of non-ASCII keys - see the specification that lists all the possible key values, which are human-readable strings like "Backspace" and "Delete" and include values for everything from modifier keys specific to Japanese keyboards to obscure media keys. Another, which is highly relevant to this question, is distinguishing between the meaning of a modified keypress and the physical key that was pressed.
On small Mac keyboards, there is no Delete key, only a Backspace key. However, pressing Fn+Backspace is equivalent to pressing Delete on a normal keyboard - that is, it deletes the character after the text cursor instead of the one before it. Depending upon your use case, in code you might want to handle a press of Backspace with Fn held down as either Backspace or Delete. That's why the new key model lets you choose.
The .key attribute gives you the meaning of the keypress, so Fn+Backspace will yield the string "Delete". The .code attribute gives you the physical key, so Fn+Backspace will still yield the string "Backspace".
Unfortunately, as of writing this answer, they're only supported in 18% of browsers, so if you need broad compatibility you're stuck with the "legacy" .keyCode attribute for the time being. But if you're a reader from the future, or if you're targeting a specific platform and know it supports the new interface, then you could write code that looked something like this:
document.getElementById('foo').addEventListener('keydown', function (event) {
if (event.code == 'Delete') {
console.log('The physical key pressed was the DELETE key');
}
if (event.code == 'Backspace') {
console.log('The physical key pressed was the BACKSPACE key');
}
if (event.key == 'Delete') {
console.log('The keypress meant the same as pressing DELETE');
// This can happen for one of two reasons:
// 1. The user pressed the DELETE key
// 2. The user pressed FN+BACKSPACE on a small Mac keyboard where
// FN+BACKSPACE deletes the character in front of the text cursor,
// instead of the one behind it.
}
if (event.key == 'Backspace') {
console.log('The keypress meant the same as pressing BACKSPACE');
}
});
In your function check for the keycode 8 (backspace) or 46 (delete)
Keycode information
Keycode list
not sure if it works outside of firefox:
callback (event){
if (event.keyCode === event.DOM_VK_BACK_SPACE || event.keyCode === event.DOM_VK_DELETE)
// do something
}
}
if not, replace event.DOM_VK_BACK_SPACE with 8 and event.DOM_VK_DELETE with 46 or define them as constant (for better readability)
I need to change in a text input the character '.' to ',' while typing.
In IE I change the keyCode event property in the keypress event, like this
document.getElementById('mytext').onkeypress =
function (evt) {
var e = evt || window.event;
if (e.keyCode && e.keyCode==46)
e.keyCode = 44;
else if (e.which && e.which==46) {
e.which = 44;
}
};
but it seemes that in Firefox it's impossible to change characters typed in key events.
Any suggestions?
Try this. It works on all browsers:
window.onload = function () {
var input = document.getElementById("mytext");
input.onkeypress = function () {
var evt = arguments[0] || event;
var char = String.fromCharCode(evt.which || evt.keyCode);
// Is it a period?
if (char == ".") {
// Replace it with a comma
input.value += ",";
// Cancel the original event
evt.cancelBubble = true;
return false;
}
}
};
Update: Pier Luigi pointed out a problem with the above. It doesn't take care of the caret position not being at the end of the text. It will append the command to the end even if you're inserting some text to the value.
The solution would be, instead of appending a comma, to simulate a keypress event for the comma key. Unfortunately the way dispatching of synthetic events work in different browsers seems to show a lot of variety and isn't an easy feat. I'll see if I can find a nice and generic method for it.
Assume that all properties in an Event object are immutable. The DOM spec doesn't address what happens when you change those values manually.
Here's the logic you need: listen for all key events. If it's a period, suppress the event, and manually add the comma at the cursor position. (Here's a code snippet for inserting arbitrary text at the cursor position.)
You'd suppress the event in Firefox by calling event.preventDefault(); this tells the browser not to go ahead with the default action associated with this event (in this case, typing the character). You'd suppress the event in IE by setting event.returnValue to false.
If it's not a period, return early from your handler.
Technically you just want to replace all dots with commas.
document.getElementById('mytext').onkeyup = function(){
this.value = this.value.replace('.', ',');
}
If I look at the official Document Object Model Events document, mouse events fields are defined as read-only. Keyboard events are not defined there, I suppose Mozilla followed this policy for them.
So basically, unless there is some smart trick, you cannot alter an event the way you want. You probably have to intercept the key and insert the char (raw or translated) where the caret is, the way JS HTML editors do.
Does this really need to be done on the fly? If you are collecting the information to be posted to a form or submitted to a database, would it not be better to modify the data once it was submitted? That way the user never sees the confusing change.
This is possible now by intercepting and cancelling the default keydown event and using HTMLInputElement.setRangeText to insert your desired character. This would look something like this:
document.addEventListener('keydown', $event => {
if($event.code === 'Period'){
$event.preventDefault();
let inputEl = document.querySelector("#my-input");
inputEl.setRangeText(
',',
inputEl.selectionStart,
inputEl.selectionEnd,
"end"
);
}
})
setRangeText will insert text at the cursor position in a given input. The "end" string as the last argument sets the cursor to the end of the inserted content.
More info here: https://developer.mozilla.org/en-US/docs/Web/API/HTMLInputElement/setRangeText