15

我正在将选项datalist动态加载到 HTML5 元素中。但是,浏览器会尝试datalist在选项加载之前显示。这会导致列表不显示或有时显示部分列表。加载选项后,有什么方法可以通过 JavaScript 刷新列表?

HTML

<input type="text" id="ingredient" list="ingredients">
<datalist id="ingredients"></datalist>

JavaScript

$("#ingredient").on("keyup", function(event) {
    var value = $(this).val();
    $.ajax({
        url: "/api/ingredients",
        data: {search: value.length > 0 ? value + "*" : ""},
        success: function(ingredients) {
            $("#ingredients").empty();
            for (var i in ingredients) {
                $("<option/>").html(ingredients[i].name).appendTo("#ingredients");
            }
            // Trigger a refresh of the rendered datalist
        }
    });
});

注意:在 Chrome 和 Opera 中,仅当用户在输入文本后单击输入时才会显示整个列表。但是,我希望整个列表显示用户类型。Firefox 不是问题,因为它似乎会在更新选项时自动刷新列表。

更新

我不确定这个问题有一个令人满意的答案,因为我相信这只是某些浏览器的一个缺点。如果 adatalist被更新,浏览器应该刷新列表,但有些浏览器(包括 Chrome 和 Opera)根本不这样做。黑客?

4

7 回答 7

5

很长一段时间后,但我找到了 IE 和 Chrome 的解决方法(未在 Opera 上测试,对于 Firefox 已经可以了)。

解决方案是将输入集中在成功(或完成)函数的末尾,如下所示:

$("#ingredient").on("keyup", function(event) {
var _this = $(this);
var value = _this.val();
$.ajax({
    url: "/api/ingredients",
    data: { search: value.length > 0 ? value + "*" : "" },
    success: function(ingredients) {
        $("#ingredients").empty();
        for (var i in ingredients) {
           $("<option/>").html(ingredients[i].name).appendTo("#ingredients");
        }
        // Trigger a refresh of the rendered datalist
        // Workaround using focus()
        _this.focus();
    }
});

它适用于 Firefox、Chrome 和 IE 11+(可能是 10)。

于 2016-01-10T17:18:13.803 回答
3

更新数据列表时我遇到了同样的问题。

直到新的输入事件才会显示新值。

我尝试了所有建议的解决方案,但没有使用 Firefox 和通过 AJAX 更新数据列表。

但是,我解决了这个问题(为简单起见,我将使用您的示例):

<input type="text" id="ingredient" list="ingredients" **autocomplete="off"**>
<datalist id="ingredients"></datalist>

$("#ingredient").on("**input**", function(event) { ....}

自动完成和输入是解决我的问题的一对,它也适用于 Chrome。

于 2019-04-24T12:45:15.197 回答
1

如果您不在每次击键时都发出 AJAX 请求,您可能可以消除该问题。您可以尝试使用节流技术set/cleatTimeout在输入最后一个字符后 500 毫秒后发出请求:

$("#ingredient").on("keyup", function(event) {

    clearTimeout($(this).data('timeout'));

    $(this).data('timeout', setTimeout($.proxy(function() {

        var value = $(this).val();

        $.ajax({
            url: "/api/ingredients",
            data: {search: value.length > 0 ? value + "*" : ""},
            success: function(ingredients) {
                $("#ingredients").empty();
                for (var i = 0; i < ingredients.length; i++) {
                    $("<option/>").html(ingredients[i].name).appendTo("#ingredients");
                }
            }
        });

    }, this), 500));
});
于 2014-10-28T14:42:06.837 回答
1

Yoyo给出了正确的解决方案,但这里有一种更好的方式来将插入结构插入到 DOM 中。

$("#ingredient").on("keyup", function(event) {
var _this = $(this);
var value = _this.val();
$.ajax({
    url: "/api/ingredients",
    data: { search: value.length > 0 ? value + "*" : "" },
    success: function(ingredients) {
        var options = ingredients.map(function(ingredient) {
          var option = document.createElement('option');
          option.value = ingredient.name;
          return option;
        });
        $("#ingredients")
          .empty()
          .append(options);
        // Trigger a refresh of the rendered datalist
        // Workaround using focus()
        _this.focus();
    }
});

更少的 DOM 操作

通过这种改进,每次成功的回调我只插入一次 DOM。这减少了需要重新渲染的浏览器,并有助于改善视图中的任何“光点”。

函数式编程和较少惯用的 jQuery

在这里,我们使用Array.prototype.map来清理一些 jQuery 并使事情变得不那么惯用。您可以从ECMA 图表中看到,此功能适用于您所针对的所有浏览器。

不哈克

这绝不是hacky。IE 似乎是唯一不会自动刷新输入以显示新列表选项的浏览器。focus() 只是一种确保输入重新聚焦的方法,这会强制刷新视图。

该解决方案在我公司必须在内部支持的所有浏览器(IE10+ Chrome 和 Firefox)中运行良好。

于 2016-05-11T16:11:56.723 回答
0

将您的#ingredients 元素放在#container 内并尝试以下代码:

$.ajax({
    url: "/api/ingredients",
    data: {search: value.length > 0 ? value + "*" : ""},
    success: function(ingredients) {
        $("#ingredients").remove();
        var item = $('<datalist id="ingredients"></datalist>');
        for (var i in ingredients) {                
            item.append("<option>"+ ingredients[i].name +"</option>");
        }
        item.appendTo('#container');
    }
});

没有#container 和使用jQuery replaceWith() 会更好:

$.ajax({
    url: "/api/ingredients",
    data: {search: value.length > 0 ? value + "*" : ""},
    success: function(ingredients) {
        var item = $('<datalist id="ingredients"></datalist>');
        for (var i in ingredients) {                
            item.append("<option>"+ ingredients[i].name +"</option>");
        }
        $("#ingredients").replaceWith(item);
    }
});
于 2014-10-28T14:32:10.033 回答
0

我发现了一个仅在 GNOME Web (WebKit) 上测试的解决方案,该解决方案包括将输入元素的“列表”属性设置为空字符串,然后立即使用 datalist 元素的 id 再次设置它。这是示例,假设您的输入元素存储在名为 的变量中input_element

var datalist = document.getElementById(input_element.list.id);
// at this point input_element.list.id is equals to datalist.id
// ... update datalist element here
// And now the trick:
input_element.setAttribute('list','')
input_element.setAttribute('list',datalist.id)
于 2020-04-03T01:27:08.233 回答
0

您的问题是 AJAX 是异步的。

您实际上必须对您调用的 AJAX进行回调onSuccess,然后更新数据列表。当然,那么您可能没有很好的性能/仍然有“跳过”行为,您的数据列表选项落后了。

如果您的 AJAX 项目列表不是太大,您应该: 1. 使用第一个查询将整个列表加载到内存数组中,然后... 1. 使用每次应用到数组的过滤函数有一个keyUp事件。

于 2015-08-28T16:19:07.760 回答