Is there an onSelect event or equivalent for HTML <select>?

Viewed 492895

I have an input form that lets me select from multiple options, and do something when the user changes the selection. Eg,

<select onChange="javascript:doSomething();">
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

Now, doSomething() only gets triggered when the selection changes.

I want to trigger doSomething() when the user selects any option, possibly the same one again.

I have tried using an "onClick" handler, but that gets triggered before the user starts the selection process.

So, is there a way to trigger a function on every select by the user?

Update:

The answer suggested by Darryl seemed to work, but it doesn't work consistently. Sometimes the event gets triggered as soon as user clicks the drop-down menu, even before the user has finished the selection process!

36 Answers

Just an idea, but is it possible to put an onclick on each of the <option> elements?

<select>
  <option onclick="doSomething(this);">A</option>
  <option onclick="doSomething(this);">B</option>
  <option onclick="doSomething(this);">C</option>
</select>

Another option could be to use onblur on the select. This will fire anytime the user clicks away from the select. At this point you could determine what option was selected. To have this even trigger at the correct time, the onclick of the option's could blur the field (make something else active or just .blur() in jQuery).

If you really need this to work like this, I would do this (to ensure it works by keyboard and mouse)

  • Add an onfocus event handler to the select to set the "current" value
  • Add an onclick event handler to the select to handle mouse changes
  • Add an onkeypress event handler to the select to handle keyboard changes

Unfortunately the onclick will run multiple times (e.g. on onpening the select... and on selection/close) and the onkeypress may fire when nothing changes...

<script>
  function setInitial(obj){
    obj._initValue = obj.value;
  }
  function doSomething(obj){
    //if you want to verify a change took place...
    if(obj._initValue == obj.value){
      //do nothing, no actual change occurred...
      //or in your case if you want to make a minor update
      doMinorUpdate();
    } else {
      //change happened
      getNewData(obj.value);
    }
  }
</script>


<select onfocus="setInitial(this);" onclick="doSomething();" onkeypress="doSomething();">
  ...
</select>

I know this question is very old now, but for anyone still running into this problem, I have achieved this with my own website by adding an onInput event to my option tag, then in that called function, retrieving the value of that option input.

<select id='dropdown' onInput='myFunction()'>
  <option value='1'>1</option>
  <option value='2'>2</option>
</select>

<p>Output: </p> 
<span id='output'></span>

<script type='text/javascript'>
function myFunction() {
 var optionValue = document.getElementById("dropdown").value;
 document.getElementById("output").innerHTML = optionValue;
}
</script>

This may not directly answer your question, but this problem could be solved by simple design level adjustments. I understand this may not be 100% applicable to all use-cases, but I strongly urge you to consider re-thinking your user flow of your application and if the following design suggestion can be implemented.

I decided to do something simple than hacking alternatives for onChange() using other events that were not really meant for this purpose (blur, click, etc.)

The way I solved it:

Simply pre-pend a placeholder option tag such as select that has no value to it.

So, instead of just using the following structure, which requires hack-y alternatives:

<select>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

Consider using this:

<select>
  <option selected="selected">Select...</option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

So, this way, your code is a LOT more simplified and the onChange will work as expected, every time the user decides to select something other than the default value. You could even add the disabled attribute to the first option if you don't want them to select it again and force them to select something from the options, thus triggering an onChange() fire.

At the time of this answer, I'm writing a complex Vue application and I found that this design choice has simplified my code a lot. I spent hours on this problem before I settled down with this solution and I didn't have to re-write a lot of my code. However, if I went with the hacky alternatives, I would have needed to account for the edge cases, to prevent double firing of ajax requests, etc. This also doesn't mess up the default browser behaviour as a nice bonus (tested on mobile browsers as well).

Sometimes, you just need to take a step back and think about the big picture for the simplest solution.

Actually, the onclick events will NOT fire when the user uses the keyboard to change the selection in the select control. You might have to use a combination of onChange and onClick to get the behavior you're looking for.

Add an extra option as the first, like the header of a column, which will be the default value of the dropdown button before click it and reset at the end of doSomething(), so when choose A/B/C, the onchange event always trigs, when the selection is State, do nothing and return. onclick is very unstable as many people mentioned before. So all we need to do is to make an initial button label which is different as your true options so the onchange will work on any option.

<select id="btnState" onchange="doSomething(this)">
  <option value="State" selected="selected">State</option>  
  <option value="A">A</option>
  <option value="B">B</option>
  <option value="C">C</option>
</select>


function doSomething(obj)
{
    var btnValue = obj.options[obj.selectedIndex].value;

    if (btnValue == "State")
    {
      //do nothing
      return;
    }

    // Do your thing here

    // reset 
    obj.selectedIndex = 0;
}

What I did when faced with a similar Problem is I added an 'onFocus' to the select box which appends a new generic option ('select an option'or something similar) and default it as the selected option.

Kindly note that Event Handlers are not supported for the OPTION tag on IE, with a quick thinking..I came up with this solution, try it and give me your feedback:

<script>
var flag = true;
function resetIndex(selObj) {
    if(flag) selObj.selectedIndex = -1;
    flag = true;
}
function doSomething(selObj) {
    alert(selObj.value)
    flag = false;
}
</script>
<select onchange="doSomething(this)" onclick="resetIndex(this)">
<option value="A">A</option>
<option value="B">B</option>
<option value="C">C</option>
</select>

What I'm doing here actually is resetting the select index so that the onchange event will be triggered always, true that you we lose the selected item when you click and it maybe annoying if your list is long, but it may help you in someway..

There are a few things you want to do here to make sure it remembers older values and triggers an onchange event even if the same option is selected again.

The first thing you want is a regular onChange event:

$("#selectbox").on("change", function(){
    console.log($(this).val());
    doSomething();
});

To have the onChange event trigger even when the same option is selected again, you can unset selected option when the dropdown receives focus by setting it to an invalid value. But you also want to store the previously selected value to restore it in case the user does not select any new option:

prev_select_option = ""; //some kind of global var

$("#selectbox").on("focus", function(){
    prev_select_option = $(this).val(); //store currently selected value
    $(this).val("unknown"); //set to an invalid value
});

The above code will allow you to trigger onchange even if the same value is selected. However, if the user clicks outside the select box, you want to restore the previous value. We do it on onBlur:

$("#selectbox").on("blur", function(){
    if ($(this).val() == null) { 
       //because we previously set an invalid value 
       //and user did not select any option
        $(this).val(prev_select_option);
    }
});

Another solution is using the onMouseUp event. OnMouseUp works also with the same option re-selected as well as changed option.

Only disadvantage. The code is called when the dropdown box is openemd and a second time when the selection is made. Keep that in mind for AJAX requests. If this is not harming your logic you can use it as a simple inline hack.

<select id="bla" onmouseup="console.log( document.getElementById('bla').options[document.getElementById('bla').selectedIndex].value );">
  <option value="0">A</option>
  <option value="1">B</option>
</select>

The best solution I have found is to add a disabled option as the first element within your select element so that all other items will be available to respond to click in the onchange event.

<select onchange="doSomething()">
  <option disabled selected value> -- select an option -- </option>
  <option>A</option>
  <option>B</option>
  <option>C</option>
</select>

2022 VANILLA JAVASCRIPT

...because this is a top hit on Google.

Original Poster did NOT ask for a JQuery solution, yet all answers ONLY demonstrate JQuery or inline SELECT tag event.

Use an event listener with the 'change' event.

const selectDropdown = document.querySelector('select');
selectDropdown.addEventListener('event', function (e) { /* your code */ });

... or call a seperate function:

function yourFunc(e) { /* your code here */ }

const selectDropdown = document.querySelector('select');
selectDropdown.addEventListener('event', yourFunc);

The only solution that worked for me was totally resetting the SELECT on "onFocus" event. This way, the SELECT always "changes" on "onChange" event:

$('select').on('focus', function(ev) {
    var $select = $(this);
    var options = $select.html();
    $select.empty();
    $select.append(options);
});

$('select').on('change', function(ev) {
    // Now the select element ALWAYS fires onChange
});
Related