How do you refresh an HTML5 datalist using JavaScript?

23,081

Solution 1

Quite a long time after question but I found a workaround for IE and Chrome (not tested on Opera and already OK for Firefox).

The solution is to focus the input at the end of success (or done) function like this :

$("#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();
    }
});

It works on Firefox, Chrome and IE 11+ (perhaps 10).

Solution 2

I had the same problem when updating datalist.

The new values would not show until new input event.

I tried every suggested solutions but nothing using Firefox and updating datalist via AJAX.

However, I solved the problem (for simplicity, I'll use your example):

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

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

Autocomplete and input is the couple that solve my problems and it works with Chrome too.

Solution 3

Yoyo gave the correct solution, but here's a better way to structure your inserts into the 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();
    }
});

Less DOM manipulation

With this refinement, I'm only inserting into the DOM a single time per each successful callback. This cuts down on the browser needing to re-render, and will help improve any "blips" in the view.

Functional Programming and Less Idiomatic jQuery

Here we are using the Array.prototype.map to clean up some of the jQuery and make things a bit less idiomatic. You can see from the ECMA Chart that this function will work in all browsers you are targeting.

Not Hacky

This by no means is hacky. IE appears to be the only browser that doesn't automatically refresh the input to display the new list options. focus() is just a way to ensure the input is refocused which forces a refresh of the view.

This solution works very well in all of the browsers that my company has to support internally, IE10+ Chrome and Firefox.

Solution 4

You can probably eliminate the problem if you don't make AJAX request on every key stroke. You can try throttle technique using set/cleatTimeout to issue request after 500ms after the last char typed:

$("#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));
});
Share:
23,081
David Jones
Author by

David Jones

Updated on April 04, 2020

Comments

  • David Jones
    David Jones about 4 years

    I'm loading options into an HTML5 datalist element dynamically. However, the browser attempts to show the datalist before the options have loaded. This results in the list not being shown or sometimes a partial list being shown. Is there any way to refresh the list via JavaScript once the options have loaded?

    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
            }
        });
    });
    

    Note: In Chrome and Opera, the entire list is only shown if the user clicks on the input after entering text. However, I'd like the entire list to appear as the user types. Firefox is not a problem, as it appears to refresh the list automatically when the options are updated.

    UPDATE

    I'm not sure this question has a satisfactory answer, as I believe this is simply a shortcoming of certain browsers. If a datalist is updated, the browser should refresh the list, but some browsers (including Chrome and Opera) simply do not do this. Hacks?

    • Thijs
      Thijs over 9 years
      Can't you hide or disable the list at page load, get the options, and than undisable/unhide the list?
    • David Jones
      David Jones over 9 years
      @Thijs: I'm updating the list on keyup events, so it's quite dynamic. I've updated my question to reflect this.
    • Thijs
      Thijs over 9 years
      perhaps always show one item which says "loading..." or some sort of spinning image?
    • Ragnar
      Ragnar over 9 years
      I found this example raymondcamden.com/2012/6/14/… but I don't know if it can help you.
    • David Jones
      David Jones over 9 years
      Thanks @Ragnar. His solution suffers the same problem. If you open his demo and then type "mo", then hit backspace, the list fails to update in time (but if you inspect element, the datalist has updated). Works fine in Firefox though.
    • Ragnar
      Ragnar over 9 years
      It seems to be a bug in Chrome, because it works for all other browsers
    • David Jones
      David Jones over 9 years
      Actually, Firefox seems to be the only browser that handles it correctly. Neither Chrome nor Opera refresh the list properly. Bummer.
  • Vidar S. Ramdal
    Vidar S. Ramdal over 9 years
    What is #container referring to?
  • David Jones
    David Jones over 9 years
    I think you mean <datalist> instead of <select>, but I see what you mean. You're suggesting that I replace the entire datalist instead of simply replacing the options. I'll try that...
  • Ragnar
    Ragnar over 9 years
    #container is an element for placing #ingredients element
  • Ragnar
    Ragnar over 9 years
    thanks @David, is <datalist> instead of <select>
  • David Jones
    David Jones over 9 years
    I agree that the timeout is a good idea, but it's solving a different problem. The browser still attempts to show the list before the options have finished being appended.
  • David Jones
    David Jones over 9 years
    This was a good suggestion and definitely worth a try, but unfortunately the behavior is the same. I'm still getting partial lists (and sometimes no list at all).
  • Terry
    Terry over 9 years
    Even better: use the jqXHR.done() function instead of the deprecated jqXHR.success counterpart.
  • David Jones
    David Jones over 9 years
    Thanks for the suggestion. I gave it a try, but the behavior is the same.
  • Brett Caswell
    Brett Caswell over 8 years
    sounds good, but I recommend you use native bind, and avoid proxy.. function() {}.bind(this) ... or function(param) { console.log(param.name); }.bind(this, {name: "Jason Bourne"});
  • Glen
    Glen over 7 years
    I found it worked for me! However, for my scenario I was only wanting to refresh the list if the input was at least 2 characters, pressing backspace also worked up to the point I still had 2 or more characters however less than 2 calling empty then focus did not work! My workaround was as someone else suggested was put in a dummy option (e.g. Type min. 2 chars.). Strangely the dummy item showed when I had no characters but disappeared when I had 1 character in IE 11 at least. Anyhow this is good enough!
  • user247702
    user247702 almost 7 years
    While testing I've found that Firefox stops displaying the suggestions if you type too fast. You don't even need to make async requests for it to happen, I could reproduce it with setTimeout as well. Typing one character at a time works, but type more than one before the suggestions are updated and the suggestions won't show up at all. Chrome works fine, so I'd say that Firefox support is currently unstable.
  • Davy R
    Davy R over 5 years
    @Stijn add autoComplete="off" to the input field to fix that
  • alessandro
    alessandro about 5 years
    I don't know why the comment lost a piece: <input type="text" id="ingredient" list="ingredients" autocomplete="off"> <datalist id="ingredients"></datalist>