Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

<select> change event not fired when using keyboard

Tags:

http://jsfiddle.net/rFEER/

<select id="users"> <option value="1">jack</option> <option value="2">brill</option> <option value="3">antony</option> </select>​ 

js:

$("#users").change(function(){     alert($(this).val()); })​ 

why change event not fired when using (keyup/keydown) until mouse is clicked

like image 631
mgraph Avatar asked Mar 21 '12 14:03

mgraph


People also ask

How do you handle keyboard events?

There are three different keyboard events in JavaScript: keydown : Keydown happens when the key is pressed down, and auto repeats if the key is pressed down for long. keypress : This event is fired when an alphabetic, numeric, or punctuation key is pressed down. keyup : Keyup happens when the key is released.

Which event is triggered when you click any key on the keyboard?

The keydown event is fired when a key is pressed. Unlike the keypress event, the keydown event is fired for all keys, regardless of whether they produce a character value.

Which event fires when the user presses the key?

The keypress event is fired when a key that produces a character value is pressed down. Examples of keys that produce a character value are alphabetic, numeric, and punctuation keys. Examples of keys that don't produce a character value are modifier keys such as Alt , Shift , Ctrl , or Meta .


2 Answers

why change event not fired when using (keyup/keydown) until mouse is clicked

It also fires when focus leaves the select. That's just how the change event works.

If you want proactive notification, you have to watch for change and keydown (at least, you may want click as well) and handle the case of getting an event when the value hasn't actually changed, and you have to handle the fact that some of those events (keydown, for instance) are fired before the value is changed, so you have to wait a moment before processing the event. Or see SpYk3HH's answer which uses keyup instead — that will be less proactive (not updating until key release, which could be desireable), but then you don't need the delay (setTimeout) my code below has.

Example (live copy):

HTML (I took the liberty of changing the values so it was clearer which went with each name):

<select id="users"> <option value="j">jack</option> <option value="b">brill</option> <option value="a">antony</option> </select>​ 

JavaScript:

$("#users").bind("keydown change", function(){     var box = $(this);     setTimeout(function() {         display(box.val());     }, 0); }); 

Note in 2016: bind has largely been replaced with on. In the above it you'd literally just replace "bind" with "on".

like image 80
T.J. Crowder Avatar answered Oct 06 '22 23:10

T.J. Crowder


Try changing

$("#users").change(function(){ 

to

$("#users").bind('change keyup', function(e) { 

that should bound yyour function for both, onchange event and when down or up arrow key is pressed

note, you could also use keydown, but it may not preform as expected as your code will run before the select change is made

And in case you want an infinate scrolling Select box, i have a nifty little func i wrote that so far, for me at least, works perfect and can be assigned all on its own without affecting other keyup actions, of course, and with intent on our sight, this is ment to work on the keyup, and so you still have to actually press the arrow key over and over, but it will continue to loop non stop through all options. Although, im pretty sure it'll work with keydown too, but we dont use it that way, so i've not tested it. Again, keydown, may not perform as intended, especially if the select only has 2 or 3 options.

function selectInfinateScroll() {     if ($(this).data("lastSelected")) {         if ($(this).data("lastSelected")[0] == $(this).children("option:selected")[0]) {             if ($(this).children("option:selected").index() == 0) {                 $(this).children("option:selected").prop("selected", false);                 $(this).children("option:last-child").prop("selected", true).change();             }             else {                 $(this).children("option:selected").prop("selected", false);                 $(this).children("option:first-child").prop("selected", true).change();             };         };     };     $(this).data("lastSelected", $(this).children("option:selected")); }  $(function() {     //  Enable 'Scrolling Through' on Select Boxes     $("select").keyup(selectInfinateScroll); }); 

UPDATED!


I'm leaving the original answer, as it uses an alternate method that may be more useful to some. However, I have come up with both a shorter function that works on "keydown" and a jQuery plugin using said function that allows user to "hold down" and arrow key and still sort through options infinitely!

First, the new function

function keydownInfiniteSelect(e) {     var eKey = e.which || e.key,         selected = $(this).find("option:selected");     if (eKey == 38 && selected.is(":first-child")) {    //    up arro         $(this).find("option").last().prop("selected", true);    //    set value to last option         $(this).change();    //    ensure select triggers change do to return false         return false;    //    keeps select from skipping to second last option     }     else if (eKey == 40 && selected.is(":last-child")) {    //    down arro         $(this).val($(this).find("option").first().val());    //    set value to first option         $(this).change();    //    ensure select triggers change         return false;    //    keeps select from skipping to second option     } } 

Use like: $("select").keydown(keydownInfiniteSelect);

And the jQuery Plugin Style!

(function($){$.infiniteSelect||($.extend({infiniteSelect:function(b){return b.each(function(){$(this).data("infiniteSelect")||($.fn.on?$(this).on("keydown",$.infiniteSelect.methods.keydownInfiniteSelect).data("infiniteSelect",!0):$(this).bind("keydown",$.infiniteSelect.methods.keydownInfiniteSelect).data("infiniteSelect",!0))})}}),$.fn.extend({infiniteSelect:function(){return $.infiniteSelect($(this))}}),$.infiniteSelect.methods={keydownInfiniteSelect:function(b){b=b.which||b.key;var c=$(this).find("option:selected"); if(38==b&&c.is(":first-child"))return $(this).find("option").last().prop("selected",!0),$(this).change(),!1;if(40==b&&c.is(":last-child"))return $(this).val($(this).find("option").first().val()),$(this).change(),!1}})})(jQuery); 

Use as $("select").infiniteSelect() OR $.infiniteSelect("select")

jsFiddle of Plugin Minified

Uncut Plugin Fiddle

PS. I almost have a Vanilla JavaScript ready for the function except that the "set to last option" part of the method keeps dieing, or going null, or skipping to the second to last. I just can't seem to get it to set correctly. If anyone wants to fix it and update, I'd be much obliged. See HERE

like image 35
SpYk3HH Avatar answered Oct 06 '22 23:10

SpYk3HH