Select2 4.0.0 AJAX - 使用Tab选择突出显示的选项

Mik*_*hay 9 ajax jquery preventdefault jquery-select2-4

我通过AJAX获取用户ID和名称,并使用Select2搜索它们,但是我的用户已经请求能够通过按Tab键从typeahead下拉列表中进行选择,有效地将其视为按Enter键.这是我的select2声明:

$("#user-select").select2({
    ajax: {
        url: "/api/User",
        method: "get",
        data: function (params) {
            return {
                search: params.term
            };
        },
        beforeSend: function () {
            $(".loading-results").text("Loading...");
        },
        processResults: function (data) {
            return {
                results: data
            };
        },
        cache: true
    },
    allowClear: true,
    placeholder: "Enter a User ID or Name",
    templateResult: function (data) {
        return "(" + data.id + ") " + data.name;
    },
    templateSelection: function (data) {
        return "(" + data.id + ") " + data.name;
    }
Run Code Online (Sandbox Code Playgroud)

每当下拉列表可见时,".select2-search__field"似乎都是焦点元素,突出显示的元素将获得类"select2-results__option - highlight".

我已经尝试了一些解决方案,但似乎没有任何效果,特别是因为这个元素在下拉列表打开时出现并消失.不幸的是,我从我的尝试中丢失了代码,但它们主要包括在聚焦输入上触发Tab时执行preventDefault,然后在突出显示的元素上触发click事件或触发输入上的enter键.

我也试过调整selectOnClose选项,但是这看起来很麻烦,当我让它正常运行时会导致无限循环,更不用说根据按下的键来覆盖它.

[编辑]
所选解决方案有效,但不考虑指定的templateResult,而是显示"()undefined".因此,我调整它以将突出显示的答案添加为上覆选择的所选选项,然后在该选择上调用更改事件.

...(与初始select2相同)

}).on('select2:close', function (evt) {
    var context = $(evt.target);

    $(document).on('keydown.select2', function (e) {
        if (e.which === 9) { // tab
            var highlighted = context.data('select2').$dropdown.find('.select2-results__option--highlighted');

            if (highlighted) {
                var data = highlighted.data('data');

                var id = data.id;
                var display = data.name;

                $("#user-select").html("<option value='" + id + "' selected='selected'>" + display + "</option>");
                $("#user-select").change();
            }
            else {
                context.val("").change();
            }
        }
    });
Run Code Online (Sandbox Code Playgroud)

小智 11

我一直试图找到解决这个问题的方法.
主要问题是select2事件没有提供关于按下哪个键的任何信息.

所以我想出了这个hack来访问select2上下文中的keydown事件.
我一直在尽我所能地测试它,它似乎完美无缺.

selectElement
.select2({ options ... })
.on('select2:close', function(evt) {
    var context = $(evt.target);

    $(document).on('keydown.select2', function(e) {
        if (e.which === 9) { // tab
            var highlighted = context
                              .data('select2')
                              .$dropdown
                              .find('.select2-results__option--highlighted');
            if (highlighted) {
                var id = highlighted.data('data').id;
                context.val(id).trigger('change');
            }
        }
    });

    // unbind the event again to avoid binding multiple times
    setTimeout(function() {
        $(document).off('keydown.select2');
    }, 1);
});
Run Code Online (Sandbox Code Playgroud)


Dyl*_*ith 10

selectOnClose功能似乎在4.0.3中是稳定的,并且是一个更简单的解决方案:

$("#user-select").select2({
  ...
  selectOnClose: true
});
Run Code Online (Sandbox Code Playgroud)

模板的使用可能会干扰此功能,我没有使用它,所以我没有测试过.


ina*_*zed 1

我发现 Sniffdk 接受的答案不再适用于最新的 jquery 和 select2 库。它给了我一个Uncaught TypeError: Cannot read property 'id' of undefined.

我想出了以下有效的解决方案(对于单选 select2 下拉菜单):

function pickSelect2OptionOnTab() {
    let $select;
    let optionSelected;
    let select2Closing = false;

    $('select').on('select2:closing', function(event) {
        select2Closing = true;
        $select = $(event.target);
        optionSelected = $('.select2-results__option--highlighted').text();
        setTimeout(function() {
            select2Closing = false;
        }, 1);
    });

    $(document).bind('keydown', function(event) {
        if (event.key === 'Tab' && select2Closing) {
            const val = $select.find('option').filter(function() {
                return $(this).text() === optionSelected;
            }).first().prop('value');
            $select.val(val);
            $select.trigger('change');
        }
    });
}
Run Code Online (Sandbox Code Playgroud)