user1295718
user1295718

Reputation: 155

Javascript/jQuery prevent double event triggers

I have an html form.

  1. It uses keyboard navigation (with arrow keys) to move between fields including the enter key.
  2. It periodically needs to prompt the user for acceptance of information.
  3. The enter key is picked up on both the button and in the form field.

Problem: When the user hits ENTER on the accept button it is triggering double events in my form. Shifting the focus 2 fields instead of 1.

I have code that demonstrates exactly what I'm talking about here:

Original Post http://jsfiddle.net/mcraig_brs/UgUUr/1/

Modified Post http://jsfiddle.net/mcraig_brs/UgUUr/2/

Here is the sample HTML:

<button id="myButton">Press Enter On Me</button><br>
<input type="text" id="text1" class="tInput" data-index="0"><br>
<input type="text" id="text2" class="tInput" data-index="1"><br>
<input type="text" id="text3" class="tInput" data-index="2"><br>
<div id="log"></div>

Here is the sample JS:

function log ( data ) {
    $('#log').append(data + "<br>");   
}
function focusOn(index) {
    log("focusOn(index): " + index);
    $('input.tInput').eq(index).focus();   
}
function focusNext( currentIndex ) {
    log("focusNext(currentIndex):" + currentIndex);
    focusOn(currentIndex + 1);
}
function focusPrevious (currentIndex) {
    log('focusPrevious(currentIndex):' + currentIndex);
    focusOn(currentIndex - 1);
}
$('#myButton').on('click', function(e) {
    log("event:click #myButton");
    focusOn(0);
});
$('input.tInput').on('keyup', function(e) {
    switch (e.which) {
        case 13:
            log("event:ENTER key in input.tInput");
            focusNext($(this).data('index'));
            break;
        case 38:
            log("event:UP ARROW key in input.tInput");
            focusPrevious($(this).data('index'));
            break;
        case 40:
            log('event:DOWN ARROW key in input.tInput');
            focusNext($(this).data('index'));
            break;
    }   
});

When I press "ENTER" while the focus is on the button in the current code I get the following output in the log div:

event:click #myButton
focusOn(index): 0
event:ENTER key in input.tInput
focusNext(currentIndex):0
focusOn(index): 1

(At the moment in jsFiddle the only way I can get to the button is to focus on the first text field and shift+tab back to it so it has focus, so that I can press ENTER on it. But in the live code it is automatically focused for the user.)

Question: How can I prevent this type of double event from triggering? I have tried e.stopPropagation() but that did not yield the results I was looking for. When the user pressed ENTER I want the focus to advance only one field.

I have been wrestling with this for a few days so any help would be greatly appreciated. Please note that if a user clicks on the button with the mouse it works properly, it is only the ENTER key that triggers the double event.

Note: I had to modify my question slightly to better convey the constraints.

Upvotes: 0

Views: 3612

Answers (2)

allenhwkim
allenhwkim

Reputation: 27738

keyup is triggering the issue, change it to keypress

$('input.tInput').on('keypress', function(e) {
    switch (e.which) {
        case 13:
            log("event:ENTER key in input.tInput");
            focusNext($(this).data('index'));
            break;
    }   
});

from http://www.quirksmode.org/dom/events/keys.html

keypress

Fires when an actual character is being inserted in, for instance, a text input. It repeats while the user keeps the key depressed.

keyup

Fires when the user releases a key, after the default action of that key has been performed.

---- edit ---

To catch key press and keyup both, I would suggest to define it separately, http://jsfiddle.net/UgUUr/3/

$('input.tInput').on('keypress', function(e) {
    switch (e.which) {
        case 13:
            log("event:ENTER key in input.tInput");
            focusNext($(this).data('index'));
            break;
    }   
});

$('input.tInput').on('keyup', function(e) {
    switch (e.which) {
        case 38:
            log("event:UP ARROW key in input.tInput");
            focusPrevious($(this).data('index'));
            break;
        case 40:
            log('event:DOWN ARROW key in input.tInput');
            focusNext($(this).data('index'));
            break;
    }   
});

Upvotes: 4

A. Wolff
A. Wolff

Reputation: 74420

Use keypress event instead:

$('input.tInput').on('keypress', function(e) {    
    switch (e.which) {
        case 13:
            log("event:ENTER key in input.tInput");
            focusNext($(this).data('index'));
            break;
    }   
});

DEMO

Upvotes: 1

Related Questions