<select> change event not fired when using keyboard

时光总嘲笑我的痴心妄想 提交于 2019-11-30 10:59:20
T.J. Crowder

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".

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

That is the normal behaviour ...

Quoting the w3c specs

change
The change event occurs when a control loses the input focus and its value has been modified since gaining focus. This event is valid for INPUT, SELECT, and TEXTAREA. element.

Using the answers above I was able to get the behaviour I needed using:

$( "select" ).bind('keyup', function(e) {
    $(  '#' + e.target.id ).trigger('change');
});
Web Developer
$("#users").bind('change keyup', function(e) {

was enough

/*After having been searching for hours i wrote my own. */



<script>
jQuery(document).ready(function () {
        /*********** SELECT PLZ ****************/
        /*********** SELECT PLZ ****************/
        /*********** SELECT PLZ ****************/
        jQuery('.dropedZip').html('' +
        '<select name="theName" id="theID" size="4" style="width: 184px" >' +
        '<option value="A">Choice A</option>' +
        '<option value="B">Choice B</option>' +
        '<option value="C">Choice C</option>' +
        '<option value="D">Choice D</option>' +
        '</select>');

        var nextOptValue = 0;
        var prevOptValue = 0;

        jQuery('#prop').keydown(function (e) {

            var key = e.which;
            if(key==13){
                var currOptValue = jQuery('select#theID > option:selected').val();// CURRENT
                alert('ausgesucht: '+currOptValue);
            }
            /* UP */
            if(key==38){
                var currOptValue = jQuery('select#theID > option:selected').val();// CURRENT
                if(currOptValue!=undefined){// CURRENT != undefined ?
                    prevOptValue = jQuery('select#theID > option:selected').prev('option').val();// PREV
                    if(prevOptValue!=undefined){// PREV != undefined ?
                        jQuery('select#theID > option:selected').removeAttr('selected');// REMOVE CURRENT
                        jQuery('select#theID > option[value='+prevOptValue+']').prop('selected',true);// SET PREV
                        jQuery('input#prop').val(prevOptValue);// SET INPUT VALUE : OTHER
                    }
                }
            }
            /* DOWN */
            if(key==40){
                if(jQuery('select#theID > option:selected').val()==undefined){// NULL
                    nextOptValue = jQuery('select#theID > option:first').val();// FIRST
                    jQuery('select#theID > option[value='+nextOptValue+']').prop('selected',true);// SET FIRST
                    jQuery('input#prop').val(nextOptValue);// SET INPUT VALUE : FIRST
                }else{
                    nextOptValue = jQuery('select#theID > option:selected').next('option').val();// NEXT
                    jQuery('select#theID > option:selected').removeAttr('selected');// REMOVE FIRST
                    jQuery('select#theID > option[value='+nextOptValue+']').prop('selected',true);// SET NEXT
                    jQuery('input#prop').val(nextOptValue);// SET INPUT VALUE : OTHER
                }

            }

        });
        /*********** SELECT PLZ ****************/
        /*********** SELECT PLZ ****************/
        /*********** SELECT PLZ ****************/


    });
</script>

        <input id="prop" type="text">
<div class="dropedZip"></div>
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!