0

I'm using a jQuery plugin to replace select-boxes and I want to add a hidden input if selecting an item while the shift key is held when pressing enter. My problem is that the select plugin listener is happening before my keydown listener. Is there a way to make my first on() below execute before my second on()? Or is there a way to check inside the second on() if the shift key is being held? e.shiftKey gives me undefined if I put it inside the second on(). Thanks for ideas!

var shiftHeld = false;
$(document).on('keydown', function(e) {
   if(e.which == 13) {
       shiftHeld = e.shiftKey;
    }
});

$menu = $('#menu').select2();

$menu.on('select2:close', function (e) {
    if(shiftHeld) { $('#form').append('<input type="hidden" name="shift" value="1" />'); }
    form.submit();
});
SeaBass
  • 1,584
  • 4
  • 20
  • 46
  • I think you just need a on key up handler so you can set the shiftHeld to false. With your current logic, the shiftHeld is true as soon as it is pressed once and remains that way – Huangism Jun 15 '17 at 18:14
  • @Huangism Thanks! See my comment on the post below please. – SeaBass Jun 15 '17 at 18:21

2 Answers2

1

The event model in Javascript descends from the document element to the focused element (capturing phase), then ascends again (bubbling phase).

document   ->      element    ->    document
------- CAPTURE ------|----- BUBBLING ------

You normally capture events in the bubbling phase (target element -> document). Take a look at What is event bubbling and capturing? and https://www.quirksmode.org/js/events_order.html

However, you can also set a listener to the capturing phase, so you can react to a child event from a parent element before the child notices the event.

To do so:

function handleShift(e) { shiftHeld = e.shiftKey }
document.addEventListener("keydown", handleShift, true);
document.addEventListener("keyup", handleShift, true);

This handler will be called BEFORE the event arrives to your element. Note the last parameter "true" to indicate you want to set the handler in the capturing phase.

rupps
  • 9,712
  • 4
  • 55
  • 95
  • Great! That triggered before! Thanks! Can you set the capturing phase with jQuery on keydown/keyup as well? – SeaBass Jun 15 '17 at 18:56
  • hmm i don't know for sure, on older versions you can't, maybe now is possible, but I haven't used jquery for a while – rupps Jun 15 '17 at 18:57
0

Just add keyup to your shift check so the shiftHeld value is updated when shift is released:

var shiftHeld = false;
$(document).on('keydown keyup', function(e) {
   if(e.which == 13) {
       shiftHeld = e.shiftKey;
    }
});

function closeHandler() {
    if(shiftHeld) { $('#form').append('<input type="hidden" name="shift" value="1" />'); }
    form.submit();
}

$menu.on('select2:close', setTimeout("closeHandler()",100));
mjw
  • 1,196
  • 1
  • 12
  • 19
  • Thanks! It still doesn't go inside the `if(shiftHeld)`. I think the problem is that the second `on()` is finishing before the first one. – SeaBass Jun 15 '17 at 18:20
  • I see, give me a second. – mjw Jun 15 '17 at 18:22
  • Try the above, and if this still doesn't work, can you please add an alert(shiftHeld); before if(shiftHeld) lin in closeHandler() and tell me what value is shown? – mjw Jun 15 '17 at 18:26