Is there any specific Javascript event to detect when a datalist option is selected?

0

In Javascript, it is possible, through onchange , oninput and related, to detect if a certain input is changed.

Example:

var qs = function (el) { return document.querySelector(el); }


qs("#input").addEventListener('input', function (e) {
     console.log('evento "input" %s', e.target.value);
});

qs("#input").addEventListener('change', function (e) {
     console.log('evento "change" %s', e.target.value);
});
<input type="text" id="input" />

Using the <datalist> tag you can also suggest fills to input . It is also possible to detect these changes in the input, since selecting an item from a datalist fills the target input.

Example:

var qs = function (el) { return document.querySelector(el); }


qs("#input").addEventListener('input', function (e) {
     console.log('evento "input" %s', e.target.value);
});

qs("#input").addEventListener('change', function (e) {
     console.log('evento "change" %s', e.target.value);
});
<input type="text" id="input" list="datalist"/>

<datalist id="datalist">
 <option>Bola</option>
 <option>Peão</option>
 <option>Pipa</option>
</datalist>

However, in my scenario, the following need arose: Instead of detecting changes in input , I need to know specifically, through an event, when a option of that datalist is selected.

I tried to use onclick and mousedown in the option tag that is in this datalist , but without success.

I need exactly this, not to detect the changes, but to know if the option was selected or not.

Is there a solution ready for this in Javascript?

Note : The second example I gave does not solve my problem because the event detects changes in input , not datalist > option .

    
asked by anonymous 09.05.2018 / 14:46

3 answers

2

I do not think there is

I'd say you have to check with querySelectorAll to check all options

Event change

function qs(query, context) {
   return (context || document).querySelector(query);
}

function qsa(query, context) {
   return (context || document).querySelectorAll(query);
}

qs("#input").addEventListener('change', function (e) {

    var options = qsa('#' + e.target.getAttribute('list') + ' > option'),
        values = [];
    
    [].forEach.call(options, function (option) {
        values.push(option.value)
    });

    var currentValue = e.target.value;

    if (values.indexOf(currentValue) !== -1) {
         console.log('evento "change" %s', currentValue);
    }

});
<input type="text" id="input" list="datalist"/>

<datalist id="datalist">
 <option>Bola</option>
 <option>Peão</option>
 <option>Pipa</option>
</datalist>

Event input

function qs(query, context) {
   return (context || document).querySelector(query);
}
function qsa(query, context) {
   return (context || document).querySelectorAll(query);
}
  
var timerDataList = {};//Para usar com multiplos datalist

qs("#input").addEventListener('input', function (e) {
     var listAttr = e.target.getAttribute('list');
     
     if (timerDataList[listAttr]) clearTimeout(timerDataList[listAttr]);
  
     timerDataList[listAttr] = setTimeout(executeCheckin, 100, e.target, listAttr);
});
  
function executeCheckin(target, listAttr) {
    var options = qsa( 'option', qs('#' + listAttr) ),
        values = [];
    
    [].forEach.call(options, function (option) {
        values.push(option.value)
    });
    var currentValue = target.value;
    if (values.indexOf(currentValue) !== -1) {
         console.log('evento "input" %s', currentValue);
    }
}
<input type="text" id="input" list="datalist"/>

<datalist id="datalist">
 <option>Bola</option>
 <option>Peão</option>
 <option>Pipa</option>
</datalist>
09.05.2018 / 15:58
2

There is no event that does what you ask for, but nothing prevents you from creating one. Here's a proposal.

(function () {
  var event = new Event("selected")
  var inputs = document.querySelectorAll("[list]")
  var onInput = function (evt) {
    var index = this.options.indexOf(this.input.value.toUpperCase())
    if (index != this.input.selectedIndex) {
      this.input.selectedIndex = index
      this.input.dispatchEvent(event)
    }
  };
  [].forEach.call(inputs, function (input) {
    input.selectedIndex = -1
    var wrapper = {
      input: input,
      options: [].map.call(input.list.options, function (option) {
        return option.textContent.toUpperCase()
      })
    }
    input.addEventListener('input', onInput.bind(wrapper))
  })  
})()

input.addEventListener("selected", function (evt) {
  console.log(evt.target.selectedIndex)
})
<input type="text" id="input" list="datalist"/>

<datalist id="datalist">
 <option>Bola</option>
 <option>Peão</option>
 <option>Pipa</option>
</datalist>
    
09.05.2018 / 16:09
1

You can do this by using .map . It will create an array where you check if the value of input exists in the array with indexOf . The example below is case sensitive; if you type "kite" you will not find "Kite". But if you want, this can be easily adjusted. It will also make a difference with sharp words.

var qs = function (el) { return document.querySelector(el); }

qs("#input").addEventListener('change', function (e) {

   var datalist = document.body.querySelectorAll("#datalist option");
   var opt = [].map.call(datalist, function(o){
      return o.textContent
   });
   
   var optSel = ~opt.indexOf(e.target.value) ? true : false;
   
   // se optSel for true, significa que o valor existe no datalist
   console.log(optSel);
});
<input type="text" id="input" list="datalist"/>

<datalist id="datalist">
 <option>Bola</option>
 <option>Peão</option>
 <option>Pipa</option>
</datalist>
    
09.05.2018 / 16:02