Reputation: 16015
I don't know why this appears to be so difficult to figure out. I want to be able to execute code when a key is pressed and held but only once. Instead when I use onkeypress
or onkeydown
the function that I bound gets executed repeatedly which is not what I want. How can I have the handler be executed just once when the key is held down?
Note: I don't want to embed logic into the function that will limit its execution, I want it not to be firing the event more than once no matter how long I hold the key.
Here is the demo and the code
HTML
<div id="counter">0</div>
JS
var counter = 0,
div = document.getElementById('counter');
document.body.onkeypress = function(){
div.innerHTML = counter++;
}
Notice how when you press and hold any key the counter keeps going, I want it to count just once no matter how long I hold the key, and keep in mind the notice from above.
Sorry forgot to mention removing the listener is not acceptable, I need to increase the counter by 1 every time a key is pressed but no matter how long it's held.
Upvotes: 9
Views: 12940
Reputation: 382112
You do have to use logic to avoid repetitive events on a key being pressed, because there's no specific and compatible event for key being just pressed.
More specifically, the easiest solution is to store a boolean, setting it true on key up, false on key down (after having done your action), and ignoring the key down event while it's false:
(function(){
var shouldHandleKeyDown = true;
document.onkeydown = function(){
if (!shouldHandleKeyDown) return;
shouldHandleKeyDown = false;
// HANDLE KEY DOWN HERE
}
document.onkeyup = function(){
shouldHandleKeyDown = true;
}
})();
EDIT for 2019
Now that IE is dead, you can also use the event.repeat
property, which is true when the event is a repetition.
Upvotes: 11
Reputation: 2711
The easiest way to handle this is by using the repeat
property in the event:
// I'd recommend using addEventListener instead, but
// this is as close to the original code as possible
document.body.onkeypress = function (event) {
if (!event.repeat) {
div.innerHTML = counter++;
}
}
event.repeat
is false for the very first event, and true for repeated events (the ones that are fired when you hold down a key).
Another option is to use keyup
, which is always only used once, since you can't "hold up" a key, so it's never repeated (but keyup
is a bad choice for e.g. buttons, because it can break keyboard navigation compared to keypress
).
Upvotes: 7
Reputation: 2580
This is a modified version of Denys Séguret answer
let shouldHandleKeyDown = true;
let n = 0;
document.addEventListener('keydown', function() {
if (!shouldHandleKeyDown) return;
shouldHandleKeyDown = false;
document.getElementById('counter').innerHTML = ++n;
});
document.addEventListener('keyup', function () {
shouldHandleKeyDown = true;
});
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Counter</title>
</head>
<body>
Counter : <span id=counter>0</span>
</body>
</html>
Upvotes: 0
Reputation: 438
JSFiddle: http://jsfiddle.net/ts7w58od/
1. Bind listener
2. Unbind when event is fire.
var element = document.getElementById('target'),
once = function () {
console.log('once');
element.removeEventListener('keypress', once);
};
element.addEventListener('keypress', once, false);
Upvotes: 2