How do I get the change event for a datalist?
Asked Answered
A

9

30

I am using a datalist and need to detect when the user selects something from the drop-down list. A similar question has been asked BUT I need it so that the event fires ONLY when the user selects something from the datalist. If they type something in the input then I do NOT want the event to fire. (Notice in the accepted answer to the question I linked that they bind the input, which is not what I want). I've tried (with no success):

<datalist>
    <option>Option 1 Here</option> 
    <option>Option 2 Here</option>
</datalist>


$(document).on('change', 'datalist', function(){
   alert('hi');
});

EDIT: This question is different than the suggested question because it's a completely different question.

Aelber answered 14/5, 2014 at 6:40 Comment(4)
I've searched a lot and it seems there isn't any normal approaches to do that. You can use jQuery UI's Autocomplete widget instead: jqueryui.com/autocompleteShorts
You can use this small script: github.com/aFarkas/remote-list. Although it is written to create dynamic datalist for autosuggests, it can also handle static ones. here is a fiddle: jsfiddle.net/trixta/p8LRM. (docu: github.com/aFarkas/remote-list#select-function and demo: afarkas.github.io/remote-list/demo/index.html)Hephzibah
possible duplicate of Get selected value in datalist using jQueryDiffract
@StephanMuller it's a different question.Aelber
A
15

You can manually check it on change. But you need to check change of the input of datalist.

FIDDLE

$(document).on('change', 'input', function() {
  var options = $('datalist')[0].options;
  var val = $(this).val();
  for (var i = 0; i < options.length; i++) {
    if (options[i].value === val) {
      console.log(val);
      break;
    }
  }
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

<input list="ff">
<datalist id="ff">
  <option>Option 1 Here</option>
  <option>Option 2 Here</option>
</datalist>
Appear answered 14/5, 2014 at 6:59 Comment(1)
There should be a better way to handle this. A datalist may contain entities. If I enter the same name of an existing entity, that doesn't mean the one I typed is the same as the one in the datalist. There may be other fields that differentiate one entity from another other than the name. So choosing an item from the datalist isn't the same as typing the same text in one of the list. This might sound like an edge case for a 6-year-old question, but that's what I'm dealing with right now :)Cinematograph
O
11

In browser with the inputType property on the InputEvent you can use that to filter out any unwanted onInput events. This is "insertReplacementText" on Firefox 81 and null for Chrome/Edge 86. If you need to support IE11 you will need to validate the value is valid.

document.getElementById("browser")
  .addEventListener("input", function(event){
        if(event.inputType == "insertReplacementText" || event.inputType == null) {
          document.getElementById("output").textContent =  event.target.value;
          event.target.value = "";
    }
})
<label for="browser">Choose your browser from the list:</label>
<input list="browsers" name="browser" id="browser">
<datalist id="browsers">
  <option value="Edge">
  <option value="Firefox">
  <option value="Chrome">
  <option value="Opera">
  <option value="Safari">
</datalist>
<div id="output">
</div>
Occidental answered 16/10, 2020 at 16:22 Comment(0)
M
9

The solutions above all have a big problem. If the datalist has the option of (for example) "bob" and "bobby", as soon as someone types "bob", the code immediately says it's the same as clicking "bob"... but what if they were attempting to type "bobby"?

For a better solution, we need some more information. When listening for the 'input' event on the input field:

In Chromium-based browsers, when you type, delete, backspace, cut, paste, etc. in an input field, the event that is passed to the handler is an InputEvent, whereas when you select an option from the datalist, the event is just an Event type with a property of type that equals 'input'. (This is also true during an auto-fill, at least with BitWarden).

So you can listen for an 'input' event and check to see if it's an instance of InputEvent to determine if it's from autofill (which I think should be allowed since most of the time autofill won't be filling these types of fields, and if they do, it's usually a legit choice) / datalist selection.

In Firefox, it's different, though. It still provides an InputEvent, but it has an inputType property with the value of "insertReplacementText", which we can also use. Autofill does the same thing as Chromium browsers.

So here's a better solution:

$('#yourInput').on('input', function(){
    if (
        !(e instanceof InputEvent) ||
        e.inputType === 'insertReplacementText')
    ) {
        // determine if the value is in the datalist. If so, someone selected a value in the list!
    }
});

I wish the browsers had the same implementation that had an event type/property that was exclusive to datalist selection, but they don't so this is the best I've got. I haven't tested this on Safari (I don't have access or time right now) so you should probably take a look at it and see if it's the same or has other distinguishing differences.


UPDATE:

I noticed that if you already have the full word typed up (e.g. you typed in "Firefox") and then selected the option that matched what you had typed (e.g. you selected the "Firefox" option), it would not fire an "input" event, so you would not know that one of the options was chosen at that point. So, you'll also need a keydown/keypress/keyup event listener to listen to when they press enter. In Chromium browsers, though, it actually provides a key code of undefined when you hit enter or click on an option (yes, the click makes a keyup event). In Firefox, it says you hit Enter, but it doesn't fire any events I can find when you click an option.

Millur answered 22/6, 2021 at 16:58 Comment(2)
Doesn't seem to work for me. In both Chrome and Firefox, the determine if the value is in the datalist block is executing not only when a value from the datalist is selected, but every time a character is manually typed into the input field. The reason is that in both browsers, (e instanceof InputEvent) always evaluates to false.Supermarket
It's still working just fine for me. (e instanceof InputEvent) is evaluating as true for me whenever I type, even on mobile, so I don't know why you're seeing something different.Millur
B
3

Optimized Solution

$("input").on('input', function () {
    var inputValue = this.value;
    if($('datalist').find('option').filter(function(){
        return this.value == inputValue;        
    }).length) {
        //your code as per need
        alert(this.value);
    }
});
Bumblebee answered 17/5, 2018 at 10:21 Comment(1)
This is actually not optimized if the datalist nor options ever change, since every keystroke re-initializes the $('datalist)` jQuery object and then instantiates a new array with all the options in this data list, better would be to cache the options "outside" the event handler e.g. have const myOptions = $('datalist').find('option'); above the .on instead of doing it inline in the if.Dineric
M
3

Please have look for your solution it's good to go. Have look for Demo

$(document).on('change', 'input', function(){
    var optionslist = $('datalist')[0].options;
    var value = $(this).val();
    for (var x=0;x<optionslist.length;x++){
       if (optionslist[x].value === value) {
          //Alert here value
          console.log(value);
          break;
       }
    }
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input list="data">
<datalist id="data">
    <option value='1'>Option 1 Here</option> 
    <option value='2'>Option 2 Here</option>
</datalist>
Melancholia answered 24/9, 2018 at 8:51 Comment(0)
J
0

More Optimize

$("input").on('input', function () {
  if($('datalist').find('option[value="'+this.value+'"]')){
    //your code as per need
    alert(this.value);
  }
});
Jonas answered 4/9, 2019 at 7:49 Comment(0)
J
0

This might only be Chrome, untested anywhere else!, but I see a change event triggered when an option is selected. Normally change only happens in textfields when the field loses focus. The change event triggers before the blur event IF it's a normal non-datalist change, so we have to check both: we're looking for a change that's not immediately followed by a blur:

var timer;
el.addEventListener('change', function(e) {
    timer = setTimeout(function() {
        el.dispatchEvent(new CustomEvent('datalistchange'));
    }, 1);
});
el.addEventListener('blur', function(e) {
    clearTimeout(timer);
});

And then you can listen for the custom datalistchange event like normally. Or you can just put your specific logic instead of the dispatchEvent.

jsFiddle here

Jacobian answered 23/9, 2020 at 15:1 Comment(0)
S
0
jQuery('input').on('input', function () {
  if($('datalist[id="' + jQuery(this).attr('list') + '"]').find('option[value="'+this.value+'"]')){
    //your code as per need
    alert(this.value);
  }
});

so it will find the datalist associated with the input

Suzannsuzanna answered 27/2, 2022 at 20:32 Comment(0)
L
0

8 years, and still no good answer

Simple space-suffix trick will do what you need, add &nbsp; at the end of each option, and then detect (and remove) it in "input" handler

<input list="my-options" id="my-input">
<datalist id="my-options">
  <option>Option 1 Here&nbsp;</option>
  <option>Option 2 Here&nbsp;</option>
</datalist>

<script>
$('#my-input').on('input',function (e)
{
        var v=$(e.target).val();
        if (v.slice(-1)=='\xa0')
        {
                $(e.target).val(v=v.slice(0,-1));
                console.log("option selected '"+v+"'");
        };
});
 
</script>
Limbus answered 28/11, 2022 at 8:53 Comment(1)
what were w3 guys thinkingRobotize

© 2022 - 2024 — McMap. All rights reserved.