user1295718
user1295718

Reputation: 155

Keypress Event triggering several events

I have a button and a series of text fields. I am trying to facilitate keyboard navigation. Here is what I have:

HTML

<button id="button1">Click me</button>
<input type="text" id="field1" name="field1">
<input type="text" id="field2" name="field2">
<input type="text" id="field3" name="field3">

JS/JQUERY v 1.9.1

/* If they click the button */
$('#button1').on('click', function() {
    moveToNextInputField(); /* <-- Mystical function to "focus" the next input */
});
/* If they hit "enter" on the button */
$('#button1').on('keyup', function(e) {
    if (e.which === 13) {
        moveToNextInputField();
    }
});
/* Capture keyboard input to limit to Numbers */
$('input').on('keydown', function (e) {
    switch(e.which) {
        case 48:
        case 49:
        case 50: /* All numbers, or wanted keys, etc.... */
            $(this).data('changed', true);
            break;
        default:
            e.preventDefault();  /* prevent other unwanted keys from doing anything */
            break;
    }
});
/* Capture keyboard input for keyboard navigation */
$('input').on('keyup', function (e) {
    switch (e.which) {
        /* other cases to do stuff excluded */
        case 13:
            moveToNextInputField();
            break;
    }
});

The problem I am having is that in Firefox and IE10 (possibly others), When I select the button and press "ENTER" it triggers 2 events. The first event moves the focus to the next field, and the second does the same thing. It appears that I cannot press the "ENTER" key fast enough. When I run this code and press "enter" on the button I end up in field2.

So to my question: Is it possible to "lock" an event so that it only triggers 1 event instead of several?

As a side note, if there is a better way to do this I'm all ears.


Solution:

I found my answer was a combination of things recommended.

  1. I did get rid of $('#button1').on('keyup'....). It was redundant.
  2. I added e.stopImmediatePropigation() within the $('#button').click(...) function. This solved my problem.

Here is what the solution that worked looks like:

/* If they click the button or press ENTER while focused */
$('#button1').on('click', function(e) {
    e.stopImmediatePropigation(); 
    moveToNextInputField(); /* <-- Mystical function to "focus" the next input */
});

/* Capture keyboard input to limit to Numbers */
$('input').on('keydown', function (e) {
    switch(e.which) {
        case 48:
        case 49:
        case 50: /* All numbers, or wanted keys, etc.... */
            $(this).data('changed', true);
            break;
        default:
            e.preventDefault();  /* prevent other unwanted keys from doing anything */
            break;
    }
});
/* Capture keyboard input for keyboard navigation */
$('input').on('keyup', function (e) {
    switch (e.which) {
        /* other cases to do stuff excluded */
        case 13:
            moveToNextInputField();
            break;
    }
});

Thanks all for the help.. Hopefully this helps someone else too. Cheers.

Upvotes: 1

Views: 1270

Answers (3)

Saram
Saram

Reputation: 1510

You must notice that click is kind of special event. It is generated when button function has to be triggered. So it happens usually after mousedown, ENTER or SPACE. You can apply few solutions

  1. e.preventDefault in keyUp handler when you recognize ENTER key.
  2. use mousedown instead of click
  3. remove click handler at all (ENTER and SPACE will trigger it).

btw. i also recommend use keypress not keyup - look here.

Upvotes: 1

adeneo
adeneo

Reputation: 318212

This is easy, when focusing the button and clicking enter, both the click and keyup event handlers fire.

In other words, focusing a button and hitting enter will trigger a click event on the button, so change this :

$('#button1').on('click', function() {
    moveToNextInputField(); /* <-- Mystical function to "focus" the next input */
});

$('#button1').on('keyup', function(e) {
    if (e.which === 13) {
        moveToNextInputField();
    }
});

to just:

$('#button1').on('click', function() {
    moveToNextInputField(); /* <-- Mystical function to "focus" the next input */
});

as the keyup event handler is not needed.

FIDDLE

as a sidenote, you could shorten that to:

$('#button1').on('click', moveToNextInputField);

Upvotes: 1

Nitesh Kumar Anand
Nitesh Kumar Anand

Reputation: 621

You may try jQuery's deferred to do that. Whichever fires first, you can set the deferred object to resolved. You can check for the state of the object to see if its pending to fire first time and not when already resolved.

Upvotes: 0

Related Questions