I have a quite complex product in WooCommerce with a complicated variation selector.
To simplify things you can just click on a photo of a variation you like (anywhere on the page) and have it selected for you.
So I just added an eventlistener on the photos that triggers a click on the correct variation checkbox, as soon as you click the image:
Photo_Variation1.addEventListener('click', () => {
Variation1.click()
})
This works fine, but then the browser automatically jumps to the original variation selector – because it gets focused after/during the click-event. This is rather confusing UX-wise.
So I tried for hours to find a solution. But so far my only lousy success was making it work in Safari, by adding this to the eventListener:
Variation1.blur()
I found out it doesn't work in other browsers, because there the focus event happens directly after the mousedown-event. (In Safari it's after the click.)
However, when I tried to solely trigger the mousedown function (with a "preventDefault") nothing gets selected, at all.
Do you have an idea how I can trigger a click and prevent focusing the clicked element or any another workaround that stops the browser from jumping around?
PS:
I am using JavaScript for just 8 hours, so have mercy, please. :D
You can programmatically set a checkbox as checked by doing the following:
Photo_Variation1.addEventListener('click', () => {
var myCheckBox = document.getElementById("myCheckBoxId");
if(myCheckBox.checked) {
myCheckBox.checked = false;
} else {
myCheckBox.checked = true;
}
})
Here is more info to help you as well.
https://www.w3schools.com/jsref/prop_checkbox_checked.asp
I have bound the jQuery event handler mouseover to an element with the below code:
jQuery(document).ready(function(){
jQuery('#buyout_field').mouseleave(function() {
alert('Hi!');
});
});
This works great, but then I noticed that if the user selects a value from those dropdown auto-complete menus the browser shows you of your past data you have entered that the mouseleave event fires too early for my liking. Yes, it fires at the right time (when their mouse leaves the element); however I need the function to fire only after the user has entered data into the field.
I then added the focusout handler to cover more bases with:
jQuery('#buyout_field').focusout(function() {
alert('Hi!');
});
However it's still possible the user may select a value from the dropdown list AND not click outside the text field.
Do I have any other options here at firing the function or do I have to resort to perhaps using setTimeout() to allow the user time to select something from the autocomplete list and THEN fire the function OR should I just disable autocomplete?
Fiddle: http://jsfiddle.net/wbsDy/
I am using jquery and both blur and focusout functions require an extra click after the select box is closed to fire. Is there another way to detect when the select box is immediately closed?
As #samsquanch and #bfavaretto point out in comments here, there seems to be no way to reliably detect, across the current browser generation, when a select list is closed. Which is mildly mind-boggling, but there you are.
I think you're looking for .change(). This will just after you choose any option.
$('select').on('change', function() {
// code
});
And if you want to trigger a change event on page load just try:
$('select').on('change', function() {
// code
}).change(); // trigger initial change
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");
}
});
If we consider clicking outside the selection box can be a signal of the ending selection event.
The following jQuery can do this. Here is code in fiddle
$(function () {
let flag = 0;
$("#selectId").click(function (e) {
e.stopPropagation();
if (flag === 0) {
flag = 1;
$(document).one("click", function () {
flag = 0;
alert("select end");
});
}
});
});
Html code:
<select multiple id="selectId">
<option value="volvo">Volvo</option>
<option value="saab">Saab</option>
<option value="opel">Opel</option>
<option value="audi">Audi</option>
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.
My first instinct is a little roundabout in its way to achieve this, it would be to use the code you normally use for closing a (custom) dropdown menu on press outside:
function clickInBody(){
functionToCallOnBlur();
}
function clickInBodyStop(event){
event.stopPropagation();
}
Then on your body tag you add onClick="clickInBody()" and on your select item you add onClick="clickInBodyStop(event)". This should call the event every time you click on the page, but if you click on the select tag it will stop the propagation and not call functionToCallOnBlur()
precondition: using jQuery! This will probably only solve part of your problem, but if you are looking for an event to fire when you click off an element, you can use an overlay div.
When the user clicks on the select box:
$('#mySelectBox').click(function () {
var myOverlayDiv = $('<div id="overlayDiv" class="overlayDiv"></div>')
.click(function () {
// call your "select lost focus" function here
// which should include $('#overlayDiv').remove() somewhere!
})
.show()
.appendTo(document.body);
});
Style for the overlay div:
.overlayDiv {
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
opacity:0;
z-index:1000;
}
You need to make sure that your select box menu is a higher Z-index so when the user clicks on the menu they get the menu and not the overlay div :)
The answer is "YES", there is such an event and that is called blur event. It's very general and depends on the html element.
In the case of an HTMLSelectElement, blur is called when you exit focused state on the element, meaning you've closed it.
And the same can be said with focus that it can be assumed as a substitute for an 'open' state of the HTMLSelectElement element.
Here's an example on doing something callback when you close the HTMLSelectElementelement:
var select= document.getElementById("mySelect");
function doSomethingOnBlur(event){
console.log("Yey! The select options were closed.");
}
select.addEventListener("blur", doSomethingOnBlur);
<select id="mySelect">
<option selected hidden></option>
<option>Some Item</option>
</select>
It's important to note that the options are rendered based on the state of the select. When you focus on it, it opens. And when you lose focus (blur) then it's closed. So technically, it's just a choice of words...
I have a pop up dialog that lets you write text and does stuff when you click a button. My code is below
This function works, i find the new object by looking at e.originalEvent.explicitOriginalTarget. However now i notice if i press tab this function will be called but e.originalEvent.explicitOriginalTarget will give me the same current object instead of the new object. So my dialog doesnt close if a user presses tab to leave. How do i find the correct new dom item?
$('#Area').focusout(function (e) {
if ($(e.originalEvent.explicitOriginalTarget).closest('#Area').size() == 0)
$('#Area').hide();
});
event.relatedTarget worked for me. It will give the other DOM element, within the event, if there is one.
An example would be, if you had 2 buttons controlling the same function, and didn't want their code to be executed if they were clicked consecutively. You could attach a focusout event handler and check for an ID, or a class name.
$(".buttons").on("focusout", function (event) {
if($(event.relatedTarget).prop("class").indexOf("buttons") === -1) {
//code to execute
}
});
Perhaps a better example would be the issue I had.
I created a custom drop down list, that has a button beside it. The drop down list can be opened and closed by either clicking on the list, or the button. It can also be closed be losing focus to either object.
This becomes a problem in the following scenario.
1) user opens drop down list by clicking the list object.
2) user closes drop down list by clicking the button.
What happens is the list opens, but when the user goes to close the list, the list loses focus, which closes it, but since they are clicking on the button, it opens back up. The focusout causes the two objects to cancel each other out, in this type of scenario.
By writing the focusout event, I can now set it to only trigger when the relatedTarget doesn't have the same class as the target that called the event.
$(".listControl").on("focusout", function (event) {
if($(event.relatedTarget).prop("class").indexOf("listControl") === -1) {
//Close the drop down list
}
});
http://api.jquery.com/event.relatedTarget/
Check out this question/answer How to select an element that has focus on it with jQuery
I think the reason why you don't get anything with $("*:focus"); in Firebug console is when you click the console, the element loses focus.
And if you want to tackle it with events, the opposite of focus() is blur().
Edit
Maybe you can even try a different approach. If your only concern is watching for tab key, you can use .keypress() event and watch for tab keycode which is 9.