I have a functionality which forbids users to input specific symbols into <input> tags and also convert all alphabet characters to uppercase.
Everything worked fine when I found out this bug with fast tabbing between elements.
Problem:
Whenever a user inputs a character and presses the tab key really fast, the last character won't get converted to upper case.
Note:
I still want to let users tab between inputs so just e.preventDefault() is not an option here. I need to slightly slow down the tab action with 20-30 milliseconds or so.
Code:
var $inputs = $('input[type="text"]');
$inputs.on('keyup keydown keyhold paste', function(e) {
//validate_input will return true if character is allowed and transformed into upper case
if (!validate_input(e, $(this))) {
return false;
}
if (e.which == 9) {
// i need to do something here to slightly slow down the tab process
// just to make sure the above function will execute before the default tab action.
}
});
I suggest that you use input-event instead. That is fired when the value has changed. You can do you filtering of allowed values there, and convert it to upper case. That is a much easier, foolproof, less buggy, browser independent, keyboard independent, assistive technology independent, approach to solve your problem.
Related
I am working on a WYSIWYG-like editor for equations (in combination with plain text).
Since implementing the functionalities (for equations) that I'd like to have won't work using the existing frameworks (contentEditable or document.designMode), I am now building an editor from scratch. (so far it has worked out good, I've successfully implemented most functionalities of a normal editor)
I've been using the keydown event to detect user input while in "edit-mode" (that is, when the user has clicked on the editor-area, also displaying the cursor), but the problem with that is, that when clicking "alt" or "strg" or other keys that aren't actual characters, they'll also get displayed in my editor.
Now, what I've tried is to ignore those keys by using if-statements, but there are 2 issues I see with that:
1. It may influence performance, when too many keys have to be ignored
2. I can never be sure, if there doesn't exist some exotic key, perhaps on a Mac or so, which I didn't ignore
I have also tried to use the keypress event instead, which worked mostly fine, but still displayed "Enter" and "Delete", so who knows what others keys it may display too. Also, it is labelled as "deprecated".
Are there any better ways of doing that, or will I just have to make a big list of keys to ignore?
A simple (but limited) approach would be to check if the keydown event's keyCode is between 65 (code for key 'a') and 90 (code for 'z').
If you need more than just letters though, another solution would be to check the event's key and its length. For actual characters, the key simply holds that character (so length 1). For Ctrl, Shift, etc., key will hold the full name of the key, e.g. "Control", "Shift", etc.
So, if a key is an actual character, the key property will have a length of 1.
document.onkeydown = function(e) {
var keycode = e.keyCode;
if(e.key.length == 1) {
document.querySelector("#editor").innerHTML += e.key;
}
}
<p id="editor"></p>
You can check this one too
document.addEventListener("keydown", (event) => {
console.log(event);
if (event.code === "Escape") {
console.log("abc");
}
});
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.
I am trying to edit some existing JavaScript validation code.
Using the onkeydown event, the code checks that the value in a textbox does not go past a maximum length. I cannot use <input maxlength="value" /> as there may be some formatting characters in the string that I can safely exclude from the maximum length.
The code works fine apart from when the user has pressed the insert key to turn overtype on and they have reached the maximum length. When this occurs if they place the cursor before a character and try to overwrite it the validation thinks that this will go over the limit and doesn't realise that a character will actually be replaced.
This answer states that I cannot detect if overtype is on, but doesn't provide any references. So assuming that I cannot detect overtype, is there anyway in the onkeydown event to detect if a character is going to be replaced.
I am happy with an IE only solution.
Update: onblur is not appropriate as this will let them go many characters over the limit before warning them of the maximum length. I would like to prevent them from going over the limit.
Your handler should look at the entire value and check the length. If the length is legal, return. If not, you can update the value with a substring. You may have to use caret position to determine exactly how to manipulate the string which can be tricky as it's slightly different in IE and other browsers.
This is different from what you have now which is probably preventing keypress when max length is reached. Don't prevent keypress, just trim the resulting string.
I don't think your problem is with the onblur validation, but an event you calling on key press by the sounds of it (eg preventing the user to key any more once they reach the limit) or I have misunderstood.
IF your validation is indeed onblur, you shouldn't have to worry about things like insert/overwrite being enabled, you are only interested in what the value of the input element is once the user has completed their input.
IF you are trying to stop the user if they reach this limit as they type, I would write a function to compute the actual length you are testing. For eg,
function validateMyInput() {
var myInputField = document.getElementById('myInput');
var removeAllExcludedCharsResult = myInputField.value.replace('&','');//exclude &
var totalLength = removeAllExcludedCharsResult.length;
if(totalLength < 500) { //limit of this test is 500
return true;
}
else {
return false;
}
}
Obviously change this function to what you need and maybe make it more generic by passing in the element of the input, max length and array of excluded chars to make it reusable.
UPDATE
I have tested this problem is Chrome and the insert key seems to be ignored. IE on the other hand does overkey. However, it seems page specific, for eg, if i have enabled insert on Page A, it doesn't seem to affect Page B. I found this page which seems to be able to grab the keycode event even when insert has been pressed. It might be due to the following code?
if(window.event) {
event = window.event; //where event is the javascript key event.
}
Either way, the link above seems to have accounted for the problem, hopefully it will have the answer if the above is not correct.
Hope I haven't misunderstood what the problem was and this helped.
I am completely confused here. So I am looking for a solution for the following problem:
I want to trigger some function(for now an alert box) using jQuery on an input field. Conditions are:
Input field always maintains the focus.
Input is fed from a USB device, which acts just like a keyboard input. So for 10 characters, there will be 10 keydown and keyup events.
Once input is filled with 10 characters, respective alert box should pop out.
Now the problem I am facing, how do I find out that input fed in is not equal to 10 characters, so throw an error alert box.(lets say just 5 chars came in input, how do I figure out the final count is 5, because there will be 5 keyup events)
You could show a message underneath/beside the input box instead of popping an alert box.
E.g. on every keyup event, check the string length, and if it's not 10, show that message.
If you really, really have to resort to alert box, you could do a timeout check, e.g. only perform the validation after 1000ms of key event inactivity. This could get very annoying on the user though.
You really have two problems here. One is just understanding the jQuery syntax (see the second part to my answer), and the other is - what is the best way to understand WHEN to throw up an error box.
To answer the second question first, my recommendation would be to not use an alert box to warn the user as they tend to be modal and really interrupt the flow of input. Secondly, as you said - how do you know when the person has stopped "typing." Unless you use some sort of timing mechanism (which is more trouble than it's worth), you don't. My suggestion would be to utilize a "div" within your HTML that shows there is an error UNTIL you reach 10 characters. Once that happens, you can hide the div. (And, of course, the div can be styled to look pretty in the meantime.)
So...how to do this...
Let's assuming your input field has an id of "myField." If you are using jQuery (which is in your tags), you would do something like this.
$(function() {
var keypresses = 0;
$('#myField').keyUp(function () {
keypresses++;
if(keypresses == 10) {
$('#error').hide(); // This is your div error with some error text in it.
// Do other stuff.
} else {
// Display an error.
}
});
Alternatively, if you don't want to use the keypresses variable, you can also use..
if($(this).val().length == 10) { }
The real issue is the fact that you are measuring in key press events, because not all key presses (even when the field has focus) will insert a character into field (for example returnesc). Therefore, you will need to measure the string length in order to validate the code before you start executing functions.
In actuality you don't even need jQuery to accomplish what you need, just bind the function call to a key press event, and only execute the function call if yourstring.length = 10
yourInput.onKeyPress(yourString.length = 10 && yourFunction());
Try -
$('#idofinputfield').keyUp(function () {
var length = $('#idofinputfield').val().length;
if(length <= 10){
alert("less than 10");
}else{
alert("greaterthan 10");
}
});