Is there a DOM event that fires when an HTML select element is closed?
I'm looking for a DOM event that I can listen to with JavaScript for when a select element that has been opened (but no options changed) is then closed by clicking off the select element, somewhere (anywhere) else on the page.
It's not the blur
event of the select, because the select retains focus. Likewise, it's not the focus
event of some other element or the document, or a mousedown
or click
on the window, document or body.
It's not the change
event of the select, since no option within the select has been changed.
I'm not concerned about legacy Internet Explorers - just something to work in standards compliant modern browsers. Proprietary hacks could be worth knowing though.
I've created a JSFiddle to demonstrate the problem: http://jsfiddle.net/premasagar/FpfnM/
- Click on the selectbox in the "Result" panel
- Click on the text marked "HERE" (or anywhere else) with a single click and see if any event is added to the log. There isn't an event in the latest Chrome or Firefox.
So the question is: What JavaScript could be added, to get an event logged when clicking off the selectbox?
(I've asked a similar, but different question here:
JavaScript on iOS: opening an HTML select element)
Unfortunately there's no standard event for knowing when a select box is closed or open, so your code is going to be pretty hairy with accommodations for different browsers. That said, I think it can be done, and I've gotten something working for you in Firefox using the mouseup
event:
http://jsfiddle.net/FpfnM/50/
In Firefox (and I'm assuming Chrome), you're going to need to track the state of that select pretty carefully. When an escape
key is pressed or blur
event occurs, you need to update the state to identify it as closed. I haven't implemented that in my demo, and you can see what happens if you hit escape instead of clicking off the select.
Things were easier in Safari, where a mousedown
event on the select signifies opening the select, and any close of the select is signified by a click
event.
If you find a browser where none of these events fire, you can try one additional trick. Because form widgets like select and textarea are often rendered by the OS and not inside the browser it's possible that you could interact with them and certain messages might not get down to the browser's event handler. If you were to position a transparent textarea covering the screen at a lower z-index when the select box is open, you might be able to use it to track that close click. It may be able to capture events that a browser DOM element may miss.
Update: Chrome sees a mousedown on the select when it opens and a mouseup on the document when the page is clicked with a select open. Here's a version that works with Chrome:
http://jsfiddle.net/FpfnM/51/
Again, you'll need to do some browser detection to handle the right behavior in each one. One catch with Chrome, in particular, is that no event is fired when you click on the select a second time to close it. You can detect the page click, however.
Quick Summary:
Chrome/Safari: select.mousedown on open, document.mouseup on close
Firefox: select.click on open, document.mouseup on close
IE8/IE7: select.click on open, document.mouseup on close
There are an awful lot of edge cases for other events that will signify a close (escape keypress, blur, etc.), but these are the minimum to handle the scenario where a user clicks the select box and then clicks off into the document area.
Hope this helps!
When you have more then 1 dropdown:
$("select").each(function () {
var initDropdown = $(this);
initDropdown.data("open", false);
console.log(this.name + " closed");
initDropdown.on("blur", function () {
var blurDdopdown = $(this);
blurDdopdown.data("open", false);
console.log(this.name + " closed");
});
});
$("select").bind("click", function () {
var clickedDropdown = $(this);
if (clickedDropdown.data('open') == false) {
clickedDropdown.data('open', true);
console.log(this.name + " open");
} else {
clickedDropdown.data('open', false);
console.log(this.name + " closed");
}
});
I got the following events by following the directions on your JSFiddle to the letter:
BODY, mousedown, STRONG
#document, mousedown, STRONG
window, mousedown, STRONG
SELECT, blur, SELECT
BODY, click, STRONG
#document, click, STRONG
window, click, STRONG
These are all events that were triggered when I clicked "HERE" after the select menu was already in focus and expanded. This was in the latest version of Chrome.
Shouldn't any one of these suffice for your purposes?
Edit: If you want to make sure it's your Select element that's losing focus, set a global Javascript variable, 'selectFocused', and set it to False. Set it to True when your Select menu receives focus, and set it to False when any of the above events occurs. 'selectFocused' can now be used anywhere in your code to detect whether or not your Select element currently has focus, and when it changes values, you know your Select element has been selected or unselected.