I want to get the number of characters in a textarea. This needs to update at every keystroke. So i used this simple function:
$(document).on('keyup', 'textarea', function () {
var count = $(this).val().length;
console.log(count);
});
Now the problem is, If i try to type very fast, the count repeats. We can see the repetition in console. What is the reason behind this repetition ? Also how can i avoid it ?
Here's a fiddle: https://jsfiddle.net/w6mzzfd8/
Thanks !
As per Docs:
The keypress event is sent to an element when the browser registers keyboard input. This is similar to the keydown event, except in the case of key repeats. If the user presses and holds a key, a keydown event is triggered once, but separate keypress events are triggered for each inserted character. In addition, modifier keys (such as Shift) trigger keydown events but not keypress events.
Solution:
Use keydown instead of keyup
Code:
$(document).on('keydown', 'textarea', function () {
var count = $(this).val().length;
console.log(count);
});
Working Demo
Related
Having an input element
<input type="text">
if i add keydown event on it , it will work with state x - 1 value of input e.g
var x = document.getElementsByTagName("input")[0];
x.addEventListener("keydown",function(){
alert(x.value);
},false);
if i input "a" , it will print empty string , when i add "b" it wont print "ab" but "a" ( state - 1 )
Is there any simple way how to retrieve current value not previous?
Use input instead of keydown event.
If you require older browser support then you should also listen for keyup and mouseup (drag/drop) events.
Use keyup event or keypress event.
Reason is simple, when you are typing, there are three states.
When the key is pressed and held(even for a very short time). Here, the input field is not yet updated. This is keydown
keyup is when the key is released. That is when the input field is updated.
keypress is keydown and keyup both combined. (For alphanumeric keys)
As pointed in other answers, you can use keyup or keypress or input if you don't need to cancel event.
If you do need to cancel event (conditionally) then keydown is the must.
var x = document.getElementsByTagName("input")[0];
x.addEventListener("keydown",function(e){
//alert(x.value);
console.log(x.value + String.fromCharCode(e.which || e.keyCode);
},false);
The event doesn't support character value but you can receive it from keyCode.
I would like to populate a textarea by triggering keyboard events, such as keydown (I'm doing this for a test case).
I have added a snippet (below) to show the code I'm using to create and trigger the event. The event fires, but the textarea never receives the value of keyCode which is the letter A.
What do I need to do to see the letter in the textarea? I'm currently running the snippet in the Chrome console but it should also work in IE9.
var t = document.getElementById('foo');
// Event creation
var event = document.createEvent('HTMLEvents');
event.initEvent('keydown', true, true);
event.keyCode = 65;
event.which = 65;
// Listener for demo purpose
t.addEventListener('keydown', function (e) {
document.getElementById('fired').value = e.type + ' fired';
});
// Event trigger
t.dispatchEvent(event);
<textarea id="foo"></textarea>
<br>
<input id="fired" value="">
The keydown event is fired when a key is pressed down but it's not the responsible for write the data in the DOM elements.
The thing is; If the user writes on the <textarea> first the character is added to elements value and then the keyDownevent is triggered. However in your case you're directly triggering the event so the first step which is adding the character to the value for <textarea> is not happening.
You have two options, do it in the browser way write the value and then dispatch the event
t.value = t.value + String.fromCharCode(e.keyCode);
t.addEventListener('keydown', function (e) {
document.getElementById('fired').value = e.type + ' fired';
});
Or also you can write the value of the <textarea> on the keyDown event:
// Listener for demo purpose
t.addEventListener('keydown', function (e) {
t.value = t.value + String.fromCharCode(e.keyCode);
document.getElementById('fired').value = e.type + ' fired';
});
however if you want to use this second approach for user interaction it's a nonsense because in the case that the users inputs the data, the data will be write it twice (one for the user input and the another one in the event).
Hope this helps,
Javascript sending key codes to a <textarea> element
I had a look around and this seems more relevant than my non-relevant answer before. Sorry about that. I know this is jquery, but the premise is the same.
adding this in the event would work
document.getElementById('foo').innerHTML += String.fromCharCode(e.keyCode);
here it is in pure javascript jsfiddle
Why does not the value change after triggering keydown?
In short: you can't change the value of input/texarea with dispatching KeyboardEvent programmatically.
How actually do chars come into input? On MDN you can find the description of Keyboardevent sequence (assuming that preventDefault is not called):
A keydown event is first fired. If the key is held down further and the key produces a character key, then the event continues to be emitted in a platform implementation dependent interval and the KeyboardEvent.repeat read only property is set to true.
If the key produces a character key that would result in a character being inserted into possibly an <input>, <textarea> or an element with HTMLElement.contentEditable set to true, the beforeinput and input event types are fired in that order. Note that some other implementations may fire keypress event if supported. The events will be fired repeatedly while the key is held down.
A keyup event is fired once the key is released. This completes the process.
So, keydown leads to input event by default. But that is true only for trusted events:
Most untrusted events will not trigger default actions, with the exception of the click event... All other untrusted events behave as if the preventDefault() method had been called on that event.
Basically trusted events are those initiated by a user and untrusted events are initiated with a script. In most browsers, each event has an attribute isTrusted indicating if the event is trusted or not.
And how to test KeyboardEvents on inputs then?
Well, first of all, think if you really need a KeyboardEvent handler. Maybe you can do everything in InputEvent handler. That means that you can just set the value of the input in your tests and then trigger InputEvent.
If you still need KeyboardEvent handler than it depends on what is going on in it. E.g. if you call preventDefault in certain conditions then you can check if it was called or not in a test using a spy. Here is an example with sinon as a spy and chai as assertion library.
const myEvent = new KeyboardEvent('keydown', { key: 'a' })
sinon.spy(myEvent, 'preventDefault')
document.getElementById('foo').dispatchEvent(myEvent)
expect(myEvent.preventDefault.calledOnce).to.equal(true)
I'm not very satisfied with the key events in javascript. I need to capture both letters for writing (I'm writing text on <canvas>) and functional keys (escape) for other commands.
In Firefox it works, because Firefox fires keypress event for any key. It's very comfortable but specification directly permits it:
If supported by a user agent, this event MUST be dispatched when a key is pressed down, if and only if that key normally produces a character value.
I disagree with that specification as I see no reason for it. But as it is now, I can't do anything about it.
Problem is that Google Chrome follows that specification and doesn't fire keypress for functional keys. It does, however, notmally fire keydown for all keys.
My program has only one key event handler. It expects event containing keyCode (the ID of the physical key and optionally charCode, the equivalent character value (for keys where it makes sense).
keydown event does not contain any character values in neither browser! It only contains the keyCode. So if you define a Ctrl+Z combination and listen for keydown event, your program will be broken for users that have QWERTZ layout - because the physical location of the key (keyCode) is still the same.
If you listen for both keydown and keypress, character events will fire twice (beacuse character first fires keydown and then keypress with proper charCode property)
What I need?
Based on the above, I need to ignore keydown event for keys that will cause keypress. Doing so, I'll be able to capture Esc in keydown and characters in keypress.
How could I possibly do it?
Relevant code:
//Keypress for character codes
div.addEventListener("keypress", function(event) {
console.log(event);
if(_this.editor.event(event)) {
console.log("Event canceled.");
event.preventDefault();
event.cancelBubble = true;
return false;
}
return true;
});
//Keydown for Esc and the likes
div.addEventListener("keydown", function(event) {
//Character events are handled by keypress
if(event.charCode!=0) //Does NOT work - in keydown, charCode is ALLWAYS 0
return true;
console.log(event);
if(_this.editor.event(event)) {
console.log("Event canceled.");
event.preventDefault();
event.cancelBubble = true;
return false;
}
return true;
});
Interactive example
I figured I spend a lot of time making JSFiddles and it doesn't really increase the odds of getting an answer, so I instead uploaded the actual project.
Click into the white square in Firefox, press T, type text, press Esc, press Esc. After seconds Esc, cursor should get back to normal. Try to draw and press Ctrl+Z.
Repeat the process in Google Chrome. The Escape will not work because it doesn't fire keypress. For some reason, the Ctrl+Z fires event with keyCode 26.
From chat and comments:
#someDoge has created a fiddle which I have expanded and which now nicely shows the situation. As you can see, you can know that a key isn't character and ignore it in keypress. But you can't know that tab isn't character and cancel it in keydown (unless you have fixed array of keycode values as #someDoge sugests in comments).
You need to listen for keyup events instead of keydown, this way you won't get two separate events generated.
Then you can handle the 2 event types with the same handler function which will either get a charCode or not, depending on if the particular key generated a 'keypress' event. As long as you prevent bubbling your handler will only be called once.
Regarding the Chrome CTRL+Z problem: I don't see how you can get a charCode if the control key is being pressed, since it seems only to generate a keyup event.
I'm working on triggering events on certain key combinations that check the value of the input they were triggered in.
The problem I'm running into is that it's possible to trigger a keypress or a keydown AND type a character without triggering a keyup.
Conversely only the keyup event can read the value of the input with the newly inputted character because both the keydown and keypress fire before the character is added into the input.
JSFiddle Demo
(Note: Press shift and any other character. If you hold shift and then press and release another character the keyup event will fire, but if you press and release shift at the same time as the other key, the keyup event will not fire.)
The only solutions I can think of are triggering the keyup event one the keydown event, but this can cause problems other places.
Unfortunately I also cannot just assume that because they pressed that key combination that the input field contains what I want, as they may enter the hotkey when there are other characters in the input.
Which leaves me with the thought that I would have to check the length of the input and if it equals zero and they just pressed that hotkey, that it would fire.
But I was wondering if there's a better way of doing this?
The Keypress event seems to fire consistently. The problematic key-combinations fail to fire Keyup, but they DO fire an Input event (which, like Keyup, comes after the input value has changed). Input, however, doesn't carry information about the actual keystroke.
I don't know what conditions you're actually looking for with regards to the contents of the input. But listening for Keypress and then getting the new input contents upon the next Input event sounds like it may be what you need.
Something like:
var hotkey = false;
var lastChar = '';
$('#in').on('keypress', function(e) {
hotkey = ((e.which > 16 || e.which < 16) && e.shiftKey);
lastChar = e.which;
});
$('#in').on('input', function(e) {
if (hotkey)
$("#out").append('<div>' + lastChar + ' + shiftKey triggered ' + '<br/> INPUT: ' + $("#in").val() + '</div>');
});
I'm trying to simulate a keypress with the below code...
jQuery('input[name=renameCustomForm]').live('keyup', function (e) {
console.log('pressed');
});
jQuery('body').click(function (e) {
console.log(jQuery('input[name=renameCustomForm]'));
var press = jQuery.Event("keypress");
press.which = 13;
jQuery('input[name=renameCustomForm]').trigger(press);
});
I got this code from other posts on SO, but it doesn't work. Anyone know why?
Update
Fixed it... it appears triggering "keypress" doesn't automatically trigger "keyup"
Normally, when a user adds something to an inout field, the following events occur:
keydown (once).
keypress (at least once, additional events uccur while the key is pressed down)
keyup (once)
When a key event is simulated, it's not necessary that all events occur in this order. The event is manually dispatched, so the normal event chain isn't activated.
Hence, if you manually trigger the keypress event, the keyup event won't be fired.
You code will trigger a keypress each time you click anywhere on the page..
For your case it might be better to use the .blur() event of the input box..
jQuery('input[name=renameCustomForm]').live('keyup', function (e) {
console.log('pressed');
}).live('blur', function(){
var self = $(this);
console.log( self );
var press = jQuery.Event("keyup");
press.which = 13;
self.trigger( press );
});