14
//...
<a href="#" id="foo-link">Foo</a>
<script type="text/javascript">

  $('#foo-link').click(function(e) {
    //...
  }

</script>
//...

Using jQuery on a HTML page, the above defined click handler is executed

  1. when the user clicks it and
  2. when the user navigates to it via Tab and hits Enter

(At least in Firefox) there seems to be no difference between the click events passed to the handler - the original key event 'magically' translates to a click event.

Is there a way to differentiate between those two cases?

To give more details on why I need to treat those two cases differently: in my particular case the click handler sets the focus to a text input field. This text input field has a keyup event handler registered which sends an AJAX request. When the click handler was triggered after the user hitting Enter on the link, the keyup event is received by the now focused text input field and the AJAX request is sent mistakenly.

rmoestl
  • 3,059
  • 5
  • 24
  • 38
  • Not sure if this is possible but in the click handler can you use `event.keyCode` to check if a key has been used? – Nunners Oct 08 '13 at 10:04
  • 1
    So in the scenario you describe, the input field will still be empty? Then why not check for _that_, and don’t make the AJAX request in that case? – CBroe Oct 08 '13 at 10:05
  • no, you can't differentiate, the raised event is by all means a MouseEvent in both cases. you should attach another listener for the enter key and prevent the other in that case – David Fregoli Oct 08 '13 at 10:05
  • @CBroe indeed I prevent sending the Ajax request by checking if the text field is empty. Didn't want to get too much into detail in the question, but here we go: the text field gets a red border indicating invalid input. But at this stage the user is somehow 'innocent'. – rmoestl Oct 08 '13 at 10:09
  • Can you please create a jsbin.com sample for it? I believe, if you press in the link, then no matter if you have set the focus to textbox, keyup will be fired on link not textbox. – Rakesh Juyal Oct 08 '13 at 10:09
  • 2
    I think the only way you can do it would be to attach another listener for a key event, and then, if it's the enter key, prevent the click event from firing: http://jsfiddle.net/8m5js/ – billyonecan Oct 08 '13 at 10:11
  • @RakeshJuyal the `keyup` is definitely received by the now focused text field. At least in my environment which is Firefox on a Mac. – rmoestl Oct 08 '13 at 10:12
  • @billyonecan thanks, might be a viable workaround – rmoestl Oct 08 '13 at 10:18
  • Check this, related, http://stackoverflow.com/questions/1639338/why-does-returning-false-in-they-keydown-callback-does-not-stop-the-button-click – Sergio Oct 08 '13 at 10:51

8 Answers8

14

Is there a way to differentiate between those two cases?

Yes, there is (at least in Chrome):

$('#foo-link').click(function(event) {
    if (event.originalEvent.detail === 0) {
        // keyboard "click" event
    } else {
        // mouse "click" event
    }
}

You can check the detail property of the original event to get the click count. If the click count is 0, you know that the "click" came from the keyboard. If the click count is greater than 0, you know that the "click" came from the mouse.

Reference: https://developer.mozilla.org/en-US/docs/Web/API/UIEvent/detail

TJ Markham
  • 171
  • 1
  • 5
  • This looks like a good solution to me. However, how do we achieve this on Firefox? – Ishwar Patil Oct 18 '18 at 11:56
  • It’s widely supported (IE10+). I just came to the same solution after a lot of trials and errors. I made this pen that allows you to test, with explanations: https://codepen.io/meduzen/pen/QWjrEWx – meduz' May 09 '20 at 19:27
  • Saying it's "widely supported" is very incorrect, especially the "IE10+" part. While the `event.detail` property exists, for `click` events it is always set to 0 in both ie10 and ie11. I recently had this issue at my job, as well as caniuse also saying that it is only partially supported in ie10/11: https://caniuse.com/mdn-api_uievent_detail – Deanveloper May 24 '21 at 20:56
3

One solution is to handle 'mouseup' instead of click:

<a href="javascript:;" id="foo-link">Foo</a>
<script type="text/javascript">

      $('#foo-link').mouseup(function (e) {
              alert("Mouse click");
      });

</script>

The other solution is to handle both 'click' and 'keypress' and to return false if 'enter' is pressed:

<a href="javascript:;" id="foo-link">Foo</a>
<script type="text/javascript">

    $('#foo-link').click(function (e) {
        alert("Mouse click");
    });

    $('#foo-link').keypress(function (e) {
        if (e.which == 13)
            return false;
    });

</script>
iTURTEV
  • 331
  • 1
  • 4
3

If the event detail is === 0, it was fired by keyboard.

$('#foo-link').click(function(e) {
  // e.detail should be enough in the latest version of jQuery.
  if (e.originalEvent.detail) {
    $(this).val('Fired by mouse.');
  } else {
    $(this).val('Fired by keyboard.');
  }
});
#foo-link {
  width: 120px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="foo-link" type="button" value="Press me." />
b00t
  • 409
  • 3
  • 10
1

Probably a bit long method to handle this, but that worked : http://jsbin.com/azATuHe/3 ( Check console.log )

 $('.txtB').on('keyup', function(e){ 
    if ( $('#anSetF').data('enterpressed' ) == true ) {
      console.log ( 'keyup triggered on TEXTBOX but suppressed' );
      $('#anSetF').data('enterpressed', false )
      return true;
  }else{
    console.log ( 'keyup triggered on TEXTBOX Fire AJAX now : ' +  $('#anSetF').data('enterpressed' ) );
    //Existing code to fire AJAX
  }


  });

$('#anSetF').on('keydown.Enter', function(e){
    console.log('KEY UP: ' + e.which );
    if ( e.which == 13 ){
       $(this).data('enterpressed',true);
    }
  }).on('click', function(){
      //Some code which you used to focus the textbox
      $('.txtB').focus();
  });
Rakesh Juyal
  • 35,919
  • 68
  • 173
  • 214
0

You could just check for the presence of mouse coordinates:

function handleClick(event) {
  if (!event.originalEvent.clientX && !event.originalEvent.clientY) {
    // Enter key pressed
  }
}

The only time this wouldn't work is when the top-left most pixel of the page is being clicked. In most cases this shouldn't be an issue.

slightlyfaulty
  • 1,401
  • 14
  • 13
-1

I had something similar with my script. But I ended up with using .keyup instead of the click. It allowed me to check which button was clicked.

        $("#searching").keyup(function () {
        if (window.event.keyCode == 38 || window.event.keyCode == 40 || window.event.keyCode == 32) {
            return false;
        }
        var mystring = document.getElementById('searching').value;
        if (timeoutReference) clearTimeout(timeoutReference);
        if (!mystring.match(/\S/)) {

            $.ajax({
                    //Rest of code here..
Moelbeck
  • 591
  • 2
  • 7
  • 29
-1

This should work

$('#foo-link').keyup(function(e) {
        if(e.which == 13)
            console.log('Enter is pressed');
});
Igerko
  • 79
  • 2
  • 7
-2

Make the outline:0 for your link. Now, the user can't tab see the outline on the link. So, he wouldn't know which button he on, so he won't tap enter key but focus will be there on the element and if he presses enter, do your thing else do your thing. Even if won't set the outline:0 still the code works because focus is on it.

Mirage
  • 1,477
  • 16
  • 28