php_nub_qq
php_nub_qq

Reputation: 16015

Javascript on key press trigger only once

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.

EDIT I

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.

EDIT II

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

Answers (4)

Denys S&#233;guret
Denys S&#233;guret

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;
    }
})();

Demonstration

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

Kankaristo
Kankaristo

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

Advaith
Advaith

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

sergolius
sergolius

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

Related Questions