Attempting to log the input that the following gives me. But I am unable to even get anything other then false when attempting to type in the box. As in i'm able to type a single character, have it return true and then almost immediately it choses to no longer respond and always returns false no matter what I type inside of the box.
function search() {
var value = document.getElementById("search").value;
console.log(value == ''); // true
}
<input type="text" onkeydown="search()" id="search"></input>
Testing - Chrome 40.0.2214.94 (64-bit)
Problem is your trying to compare strings. When you do the comparison with a == it is looking at values. You need to use === then you will be able to check if the input is equal to whatever you are searching for.
Here is the updated JSFiddle
You have to use keyup event because you want result after the key is pressed.
Keyboard events is one of wilder parts of frontend development. There are inconsistencies and cross-browser problems.
But still there are recipes which help to cope with ordinary situations easily.
There are following keyboard events:
keydown
A key is pressed down.
keypress
A character key is pressed.
keyup
A key is released.
There is a fundamental difference between keypress and keydown.
Keydown triggers on any key press and gives scan-code.
Keypress triggers after keydown and gives char-code, but it is guaranteed for character keys only.
You need to use keyup, because it triggers after keypress.
<input type="text" onkeyup="search()" id="search"></input>
see KeyEvents
Related
Background:
I am writing a script that does some stuff when a user clears an input type="search" (essentially the same as type=text) using backspace or delete. I want to address the case where user highlights original text and starts typing new text, and also pasting.
Because of this I cannot use keydown (fires before input value is changed). Cannot use keypress (need to fire when backspace/delete is pressed, and it fires too early as well). Using keyup is bad because I can't clear when value === 1 (might already be several characters in the field). I can build in some slop but then it won't clear right away which looks buggy.
Question:
So the DOM input event fires right when the value is updated, which is exactly what I want (tested using jQuery on 'input'). However, I cannot find the captured key (which I need to differentiate between deleting and entering content). I couldn't find great info on the spec. It seems like this is going to be implemented in the data section of the event, which does not yet have any browser support. Does that mean it is currently impossible to get the key from the oninput event? If so, how do most developers handle this? I imagine wanting the key immediately after it is entered is very common, surely there is a decent solution for this?
Current implementation for the curious:
For the time being I am grabbing the value right after keydown by using a setTimeout of 0. This gets me both the key and the updated value, but feels dirty and requires extra handlers for onpaste and such. While writing this it occurs to me I could probably use oninput by keeping track of the last value and comparing to current to differentiate between entering and deleting, but that doesn't seem all that much better, and would still require a separate paste handler since I want my event to fire every time a user pastes, and it doesn't seem to have any flags that would let me know the event was a paste.
I decided the last suggestion of dandavis was the best workaround. I used keydown to grab key info and triggered the action on paste, empty field, or 1 character and last character was not backspace/delete (on input does not fire on enter, modifier keys, etc. so those don't need to be accounted for).
The code looks like this:
var onClear = function(action){
var lastKey;
jQueryObject.keydown(function(e){
lastKey = e.which;
});
jQueryObject.on('input', function(){
if( !this.value.length || (this.value.length === 1 && lastKey !== 46 && lastKey !== 8) ){
action();
}
});
jQueryObject.on('paste', function(){
action();
});
}
How do I prevent the user from changing a string in an input box if the combined value of that input with their latest keypress does not pass a regular expression?
I see all kinds of examples on how to use keypress for testing individual characters, but I need to match the entire value to a regular expression, not just the key they pressed.
For example, The textbox needs to conform to the following regular expression:
"^023-[0-9]{0,7}$"
So if they want to change "023" to "23", it should stop them when they delete the 0 character. The same is true for deleting the - after 023. It should also stop them once they enter more than 7 numbers after 023. This cannot be done on blur. It must be done after every key stroke. Performance is not an issue.
If I use keypress() event in jQuery, and get the value of the input element like this:
$(this).val()
Then I will only get the value before they pressed the key - not after. Thus, there is no way to test the input against my regular expression. I cannot simply append the key pressed to this string, because I cannot make the assumption that they are only entering keys at the right-most side of the string.
I have looked into keydown/keyup events, and while keyup seems to give me the current value of the input after the user has pressed a key, I am finding it difficult to remove the effects of what they typed... which keypress() does not have a problem with apparently.
var regex = new RegExp("^023-[0-9]{0,7}$");
$("#number").keyup(function(event) {
var number = $(this).val();
if(!regex.test(number)) {
event.preventDefault();
return false;
}
});
The above code just doesn't work. It seems keypress() gives me the ability to stop what they typed, but keyup gives me the ability to get the current value. I need a solution that does both ;)
The problem really stems from the fact that the browser has no MVC architecture. The model is the view. Unfortunately, we can't validate the updated model before the view is updated... because we need the view updated during a keyup event to get the updated model data... and by then, it's too late to prevent them from updating the view since it's already been updated.
How about this:
var prevValue = "";
$("#number").keydown(function(e) {
prevValue = $(this).val();
});
$("#number").keyup(function(e) {
...
if(!regex.test(number))
$(this).val(prevValue);
// show error or other processing you need to do
});
try this:
var pattern = new RegExp("^023-[0-9]{0,7}$");
$("#number").change(function(e){
if (!pattern.test($(this).val())) {
return false
}
})
The event parameter that you have will contain all the details of the event that you are handling. This will include the key that was pressed.
Of note is that keydown and keyup events will return the key pressed, while keypress will return which character is entered which may be better for your choice.
See the help page here: http://api.jquery.com/keypress/ for more details.
In summary though event.which should do what you want. You can combine that with the original value of the textbox and from that get the new value. If it isn't valid then cancel the event, if it is valid then let it go...
If you can use the jQuery Validate plug-in, you can create a custom validator to match your RegEx. Then all you have to do is map the validator to that input. You'll still have to validate on the server-side, but you're probably already doing that.
To do what you want, the jquery caret plugin is required. Please note that you'll need to remove the comments from the beginning of the file (or at least move them) or the byte order mark at the start of the code will cause an error.
So, what you need to do is capture the keypress, insert the character at the correct place in the string, check if that new string is valid and then either show the new insertion or not. I think the following does what you need:
$(document).ready(function(){
var regex = new RegExp("^023-[0-9]{0,7}$");
var caretpos;
$('#number').keypress(function(event){
// get the caret position
caretpos = $(this).caret().start;
//split the current value according to where the caret is
valuestart = $(this).val().substring(0,caretpos);
valueend = $(this).val().substring(caretpos);
// insert the fired character into the string
valuetocheck = valuestart + String.fromCharCode(event.which) + valueend;
// check if the proposed new value passes the regex
if (!regex.test(valuetocheck)) {
// failed, prevent the character being shown
event.preventDefault();
}
});
});
I've tested this in the latest versions of FF, Chrome, Safari, Opera and IE9. In FF and Opera, cursor key presses are completely ignored while they move the caret as usual in the other browsers so you may want to add some code to ensure consistent behaviour for that. You may also want to add some code to handle what will happen if the user selects some characters rather than just clicking into the input. The jquery caret plugin has usage examples for selections.
When I press a key on my keyboard, I can get the keyCode of that key using e.keyCode. But the keyCode I get does not consider the pressed alt/ctrl/shift keys, wich modify the key code.
Fortunately, I get the properties shiftKey/altKey/ctrlKey with the event so I am able to calculate the "true" key code.
But I don't know how to calculate this correctly. Where can I read about that?
Is it as easy as substracting 32 if shift ist pressed and so on, or are there much exceptions?
You're mistaken, key codes don't change because they refer to a specific key on the keyboard. Regardless of modifier keys, those codes stay the same (and even the modifier keys themselves have a key code).
Capture the keypress event, which will allow you to access character codes.
el.onkeypress = function (evt) {
alert( (evt || window.event).charCode );
}
I don't understand why you would like to calculate the "true" keyCodes. If you are making shortcuts for your site/app/whatever, you could simply check if the button was pressed was (for example) S and that Ctrl was pressed at the same time.
True keyCodes have no meaning by itself (unless you need it for something specific).
Btw, you should consider using jQuery for your project. It normalizes the keyCodes so you don't have any weird behavior in any browser (Windows and OS). I guess that is more important.
I'm trying to intercept the command + keystroke in Safari. I've added an event handler as follows:
document.onkeypress = handleKeyPress;
function handleKeyPress(event) {
if ("+" === String.fromCharCode(event.charCode) && event.metaKey) {
// my code here
return false;
}
return true;
}
When I hit command shift = (shift = is + on my US keyboard), the if statement does not return true.
If I remove the event.metaKey portion of the if statement and hit shift =, the if statement does return true.
Also, if I change the matching string from "+" to "=" and hit command = (with or without the shift key), the if statement does return true.
Is there a way to actually detect the command + keypress (without assuming that the + key is shift = and checking for the event.shiftKey, since this will not be true for some non-US keyboards)?
First of all, I can't necessarily recommend using ⌘+ as a shortcut, since it already means something in Safari (namely, zoom the page). Someone might want that to still work normally. Depending on what you're building, it might make sense, but don't override the default shortcuts unless you're sure.
Anyway: Key events are tricky, often because the keyCode/charCode/which properties don't always match up with the right letter, so String.fromCharCode won't always get you a proper string. keyIdentifier is sometimes a better thing to look at, but not always (for instance, its codes for letter keys are always uppercase letters).
What I've done in the past (and I'm not sure that this is the best way to do it, but it works ok), is to instead listen for keydown and keyup events, and "stack" modifier keys. I.e. whenever a key is depressed, check whether it's a modifier key (i.e. if it's cmd, ctrl, alt, or shift). If it is, add it to the "stack" of modifiers. Do the opposite on keyup; if the released key was a modifier, remove it from the stack.
Now, back in the keydown-handler, if the key wasn't a modifier key, you can send the keydown event (which, unlike a keypress event, will have a pretty reliable keyIdentifier property to check), and the stack of modifiers along to some other callback, that'll take it from there.
In your case, such a callback would check that the cmd-key is in the stack, and that the keyIdentifier for the keydown event is "U+002B" (which is the unicode code for +).
I've put together a jsfiddle example of what I'm talking about. If you click in the "Result" pane (to make sure it's got focus), and press ⌘+, it should show the key combo you used, and write "Success!" below. Otherwise, it'll just show the key combo. On my keyboard, the plus sign is directly accessible, so the key combo I see is just "⌘+". But if you need shift to type a plus sign, you should see "⇧⌘+".
It's a generalized piece of code that's good for handling keyboard shortcuts in Safari/Mac, so you can build on it, if you want. You'll want to add a few event listeners to reset the modifier stack on blur events and such. Ideally, the modifier stack would reset automatically, as you release the keys, but since something might cause the browser, or the observed element/window/document, to lose focus, the keyup events won't be handled, and the released keys won't be removed from the stack. So check for blur events.
Register the event object in a window object level one, event = window.EE for example, then browse it with Firebug or Safari’s Web Developer Tools and see the values that are triggered when you want. So you will know what to compare against.
Sadly, I don't think there is an answer. The problem is, for CMD+SHIFT+= the charCode being pressed is 61 (=), not 43 (+). This appears to be a system-wide design, in that Mac OS X itself interprets CMD+SHIFT+= as = plus two modifiers, not + and COMMAND.
I put together a simple jsFiddle to show this: http://jsfiddle.net/ScuDj/1/
Basically, you are going to have to deal with keyboard layouts if you want to detect COMMAND +.
Alternatively, you could only support the numeric keypad + - that works consistently! (just kidding ;-)
(Also: I tried to attach to the textInput event, but couldn't get it to register globally. I think it only works on domNodes. I've not really used that event much.)
I found this question. However, most of the answers intercept the key press, check the key code, and stop the event if it isn't an acceptable key code.
There are a some problems with that.
A common bug among all the answers is that shift key combinations are not prevented so users can enter stuff like "#" or "&".
Users can still paste in bad values from the clipboard.
When you start messing around with the key press event, the webpage starts doing weird, unexpected things. For example if the field has focus and the user tries to reload the page by pressing command-R it won't work. Or they can't tab out of the field.
I would like a solution that allows the keypress, then checks the entered value against a regex and removes unwanted characters.
I'm looking for a solution along these lines:
Doesn't intercept the keypress event.
Ideally uses a regex after the keypress.
OK if it uses jQuery.
Doesn't require installing a plug-in.
I tried this function:
$('input.numerals_only').keypress(function() {
var v = $(this).val();
var no_nonnumerals = v.replace( /[^0-9]/, '' );
$(this).val(no_nonnumerals);
});
But that doesn't work. I'm still able to type in letters.
Any info on why it doesn't work? How could I modify it so it works? Other suggestions?
If you use keyup and also blur you should handle most cases. Someone keys in text and also if they paste in a value into the text box. As the blur function will remove the bad values as well.
$('input.numerals_only').keyup(AllowOnlyNumber).blur(AllowOnlyNumber);
function AllowOnlyNumber()
{
var v = $(this).val();
var no_nonnumerals = v.replace(/[^0-9]/g, '');
$(this).val(no_nonnumerals);
}
Of course if html5 is an option you could always do:
<input type="number"/>
jsfiddle example.
The thing your regexp is missing, which is why it didn’t work for keypresses neither, is the g flag for a global regexp check.
Use var no_nonnumerals = v.replace( /[^0-9]/g, '' );
If you use keyup instead of keypress it will always remove the incorrect characters.
You can also use this to actually block the events:
$('input.numerals_only').keypress(function(event) {
if(event.keyCode < 48 || event.keyCode > 57){
return false;
}
});
Use the keyup event. It is triggered after the key is processed by the browser:
$('#txtInput')
.keyup(function(ev) {
var newValue = this.value.replace(/[^0-9]/, '');
$(this).val(newValue);
});
I wrote a jQuery plugin to do this. Demo and code here http://brianjaeger.com/process.php
It uses a regular expression to validate whatever you want.
There are a few issues:
it's a plugin (however, you could suck out the code and plunk it into your other JavaScript if you want. -its easier just to use as plugin)
Unfortunately there is no way to limit pasted information directly (across all browsers) - My solution to this was to add validation on focus change as well as keypress.