2

Is there a way to trigger an event when an HTML select list is dropped down? I'm not asking about when it closed, but when you first drop it down.

I'd like to set the selectedIndex = -1 when the user clicks on the down arrow of the drop-down.

Most websites begin their drop-down with a blank entry, or a dummy entry like "Select...". I'd like to just have the values themselves, and have the list clear itself whenever they click in.

This is what I started with, but it fires after they make a choice, which isn't what I want - I want only when the list drops down.

<select id="ddlMylist">
  <option value="10">Choice 1</option>
  <option value="20">Choice 2</option>
  <option value="30">Choice 3</option>
  <option value="40">Choice 4</option>
</select>


document.getElementById("ddlMylist").onclick = function(){
  //this clears the list when they click, but it fires when they
  //are making an actual choice, which isn't what I want
  document.getElementById("ddlMylist").selectedIndex=-1;
  }

This JSFiddle tries to use a click event, but of course that doesn't let the user actually make a choice.

JosephStyons
  • 57,317
  • 63
  • 160
  • 234
  • Possible duplicate of [Is there a DOM event that fires when an HTML select element is closed?](https://stackoverflow.com/questions/6207929/is-there-a-dom-event-that-fires-when-an-html-select-element-is-closed) – Jeto Dec 26 '18 at 20:59
  • 2
    Why would you want to clear the selection whenever a user clicks on a dropdown though? Sounds hella annoying/counter-intuitive to me. – Jeto Dec 26 '18 at 21:00
  • @Jeto - this is a common design pattern in winforms apps, and the users in this case are accustomed to it. Personally I think it makes sense. If you are clicking the drop-down, then it seems logical to assume that you do not like the current selection, so putting you back at a "blank" state seems reasonable. – JosephStyons Dec 27 '18 at 17:19
  • It's bad UX to me. I sometimes do this to check what the other options are/were, just to be sure, and would be very frustrated if that cleared my selection every time. I don't see the problem with the default behavior of dropdown lists. If that's how they behave, it's for a reason! – Jeto Dec 27 '18 at 17:45

3 Answers3

3

This can be achieved via the mousedown event, which is fired when the user first initates the click on the <select> element:

// mousedown is fired when mouse click is first pressed down on
// the <select> element 
document
.getElementById("ddlMylist")
.addEventListener("mousedown", function(){ 
  
  // Resets selected option item
  document.getElementById("ddlMylist").selectedIndex = -1;
})
<select id="ddlMylist">
  <option value="10">Choice 1</option>
  <option value="20">Choice 2</option>
  <option value="30">Choice 3</option>
  <option value="40">Choice 4</option>
</select>

Please keep in mind that this method is tested and works in Chrome, but is not guaranteed to work in other browsers.

Dacre Denny
  • 29,664
  • 5
  • 45
  • 65
  • Doesn't work on last Firefox (guess mousedown is triggered on option selection). See the linked answer for more information. In short, there doesn't seem to be any reliable way to pull this off (no specific DOM event so you have to deal with every possible browser's way of handling the other, more generic events). – Jeto Dec 26 '18 at 21:06
  • This is exactly what I wanted, but it does seem to be Chrome-only. Thank you very much. – JosephStyons Dec 27 '18 at 17:18
  • @DacreDenny, I modified your example to make it work in all browsers. Thanks again! – JosephStyons Dec 27 '18 at 17:31
1

Don't really understand your question but these three events will clear the select tag at different stages of the interaction with it.

document.getElementById("ddlMylist").addEventListener('focus', function(){
  document.getElementById("ddlMylist").selectedIndex=-1;
  });

document.getElementById("ddlMylist").addEventListener('blur', function(){
  document.getElementById("ddlMylist").selectedIndex=-1;
  });

document.getElementById("ddlMylist").addEventListener('change', function(){
  document.getElementById("ddlMylist").selectedIndex=-1;
  });
SoMa
  • 61
  • 3
0

I modified @Dacre Denny's answer and got it to work in Firefox, Chrome, and Edge.

Link to JSFiddle.

var ClearOnClick = function(){
  document.getElementById("ddlMylist").selectedIndex = -1;
  StopListening();
};

function StopListening(){
  console.log("not listening...");
  document.getElementById("ddlMylist").removeEventListener("mousedown", ClearOnClick);
  document.getElementById("ddlMylist").addEventListener("change", StartListening);
}

function StartListening(){
  console.log("listening...");
  document.getElementById("ddlMylist").addEventListener("mousedown", ClearOnClick);
}
StartListening();

And, if you want to slap this behavior on all the select lists on a page, you can use this (JSFiddle). If anyone can see a good way to do this without calling eval() then I'm all ears.

  $("select").each(function () {
    /*
    every drop down list gets three functions - startlistening, clearonclick, and stoplistening.
    clearonclick is stored in a variable so that it can be unhooked
    Once everything is wired up, it should look like this -but repeated once for each drop down
    var ClearOnClick = function(){
      document.getElementById("ddlMylist").selectedIndex = -1;
      StopListening();
    };

    function StopListening(){
      document.getElementById("ddlMylist").removeEventListener("mousedown", ClearOnClick);
      document.getElementById("ddlMylist").addEventListener("change", StartListening);
    }

    function StartListening(){
      document.getElementById("ddlMylist").addEventListener("mousedown", ClearOnClick);
    }
    StartListening();
    */
    var controlName = this.id;
    //function names
    var cc_vname = "ClearOnClick_" + controlName;
    var sp_fname = "StopListening_" + controlName;
    var sl_fname = "StartListening_" + controlName;

    //full function bodies
    var clearOnClick_functionDeclaration = "var " + cc_vname + " = function(){document.getElementById('" + controlName + "').selectedIndex = -1;" + sp_fname + "();}";
    var stopListening_functionBody = "function " + sp_fname + "(){  document.getElementById('" + controlName + "').removeEventListener('mousedown', " + cc_vname + ");document.getElementById('" + controlName + "').addEventListener('change', " + sl_fname + ")}";
    var startListening_functionBody = "function " + sl_fname + "(){document.getElementById('" + controlName + "').addEventListener('mousedown', " + cc_vname + ");}";
    console.log(clearOnClick_functionDeclaration);
    console.log(stopListening_functionBody);
    console.log(startListening_functionBody);
    //create the functions for this drop down
    eval(clearOnClick_functionDeclaration);
    eval(stopListening_functionBody);
    eval(startListening_functionBody);

    //kick off by calling the start listening function
    console.log(sl_fname + "();");
    eval(sl_fname + "();");
  });
JosephStyons
  • 57,317
  • 63
  • 160
  • 234