【问题标题】:How do you refresh an HTML5 datalist using JavaScript?如何使用 JavaScript 刷新 HTML5 数据列表?
【发布时间】:2014-12-24 00:00:43
【问题描述】:

我正在将选项动态加载到 HTML5 datalist 元素中。但是,浏览器会在选项加载之前尝试显示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 不是问题,因为它似乎会在更新选项时自动刷新列表。

更新

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

【问题讨论】:

  • 你不能在页面加载时隐藏或禁用列表,获取选项,然后取消禁用/取消隐藏列表吗?
  • @Thijs:我正在更新keyup 事件的列表,所以它非常动态。我已经更新了我的问题以反映这一点。
  • 也许总是显示一个项目,上面写着“正在加载...”或某种旋转图像?
  • 我找到了这个例子raymondcamden.com/2012/6/14/…,但我不知道它是否对你有帮助。
  • 谢谢@Ragnar。他的解决方案遇到了同样的问题。如果您打开他的演示然后键入“mo”,然后按退格键,列表将无法及时更新(但如果您检查元素,datalist 已更新)。不过在 Firefox 中运行良好。

标签: javascript jquery ajax html html-datalist


【解决方案1】:

将您的#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);
    }
});

【讨论】:

  • #container 指的是什么?
  • 我认为您的意思是 &lt;datalist&gt; 而不是 &lt;select&gt;,但我明白您的意思。您建议我替换整个 datalist 而不是简单地替换选项。我试试看……
  • #container 是放置#ingredients 元素的元素
  • 感谢@David,是&lt;datalist&gt; 而不是&lt;select&gt;
  • 这是一个很好的建议,绝对值得一试,但不幸的是行为是相同的。我仍然得到部分列表(有时根本没有列表)。
【解决方案2】:

如果您不在每次击键时都发出 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));
});

【讨论】:

  • 我同意超时是个好主意,但它解决了另一个问题。在选项完成附加之前,浏览器仍会尝试显示列表。
  • 感谢您的建议。我试了一下,但行为是一样的。
  • 听起来不错,但我建议您使用本机绑定,并避免代理.. function() {}.bind(this) ... 或 function(param) { console.log(param.name); }.bind(this, {name: "Jason Bourne"});
【解决方案3】:

您的问题是 AJAX 异步

您实际上必须为 AJAX 设置一个 回调,您称之为 onSuccess,然后它会更新数据列表。当然,那么您可能没有很好的性能/仍然有“跳过”行为,您的数据列表选项落后了。

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

【讨论】:

    【解决方案4】:

    问了很久,但我找到了适用于 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)。

    【讨论】:

    • 在测试时我发现如果你输入得太快,Firefox 会停止显示建议。您甚至不需要发出异步请求来实现它,我也可以使用setTimeout 重现它。一次键入一个字符有效,但在更新建议之前键入多个字符,建议根本不会显示。 Chrome 工作正常,所以我会说 Firefox 支持目前不稳定。
    • @Stijn 将autoComplete="off" 添加到输入字段以修复
    【解决方案5】:

    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 Chart 中看到,此功能适用于您所针对的所有浏览器。

    不是哈克

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

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

    【讨论】:

    • 我发现它对我有用!但是,对于我的场景,我只想在输入至少 2 个字符时刷新列表,按退格键也可以达到我仍然有 2 个或更多字符但少于 2 个调用空然后焦点不起作用的程度!我的解决方法是其他人建议放在一个虚拟选项中(例如,键入最少 2 个字符。)。奇怪的是,虚拟项目在我没有字符时显示,但在 IE 11 中至少有 1 个字符时消失了。无论如何这已经足够了!
    【解决方案6】:

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

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

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

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

    <input type="text" id="ingredient" list="ingredients" **autocomplete="off"**>
    <datalist id="ingredients"></datalist>
    
    $("#ingredient").on("**input**", function(event) { ....}
    

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

    【讨论】:

    • 不知道为什么评论丢了一块:
    【解决方案7】:

    我发现仅在 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)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-11-17
      • 1970-01-01
      • 1970-01-01
      • 2018-12-28
      • 2013-11-23
      • 2013-07-11
      • 1970-01-01
      相关资源
      最近更新 更多