Very weird Chrome behavior in an open (focused) "select" element - javascript

Here's a <select> element:
<select>
<option>Hello</option>
<option>Banana</option>
<option>Balloon</option>
<option>Something</option>
<option>Potato</option>
<option>Cleveland</option>
</select>
Here's a little bit of JavaScript (a jQuery "ready" handler):
$(function() {
function foo() {
var s = $('select').find(':selected');
}
setInterval(foo, 200);
});
Here is the jsfiddle for this question..
The handler sets up an interval timer which, every 200 milliseconds, finds the currently-selected <option> of the <select>, and does nothing at all with it. When I run the fiddle in Chrome (13.0.782.112), and I click on the <select> element, and then try to select an entry, the selection highlight keeps jumping back to the first selected element. I can click on any of the <option> elements shown and that works, of course, and then it does the same thing the next time.
Now, if I change the timer handler so that it doesn't use jQuery to find the currently-selected <option> element, as follows:
$(function() {
function foo() {
var select = $('select')[0];
var s = $(select.options[select.selectedIndex]);
}
setInterval(foo, 200);
});
then I no longer see the effect.
Firefox does not do this. I haven't tried Safari yet.
Personally I think that something's doing something wrong here. Is it Chrome? jQuery?
edit — one more detail - I'm running Chrome on Linux. I'll try Windows in a sec. (edit same in Windows.)

Change the code to:
function foo() {
var s = $('select option:selected');
}
setInterval(foo, 200);
Not sure why exactly it does this, but my guess would be that it's related to the way pseudoselectors work in jQuery. They're implemented as functions which are paired with the name of the selector (In this case "selected"). Consequently they are run against every possible element in the context (not just those which could potentially be selected).
Maybe there some sort of weird ghost element against which the "selected" pseudoselector is being executed when it shouldn't. The solution here is that I restrict the context to options before doing the pseudoselector. Always a good thing to do.

Related

Simulate human selection of option item in select menu

I have a bit of script which technically works. It essentially listens to the hashtag on the URL and updates the select menu with the option value which matches the hashtag. It works on page load and doesn't care how the hashtag is updated, only that it is. Perfect
The problem is, I have a lot of other scripts on that page which does something when you select an option item, they all work when you manually select an option item, but nothing is triggered when I use the below script to automatically select the option item. How can I actually simulate a human selection in this setting? Any ideas?
$( document ).ready(function() {
window.addEventListener('hashchange', fn, false);
window.onload = fn; // fire on pageload
function fn() {
document.getElementById('select-two').value =
window.location.hash.replace('#','');
}
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<select id="select-two" name="colordrop" class="color2" onchange="letsDoThis()">
<option value="Jet" class="jet">Jet</option>
<option value="Cream" class="cream">Cream</option>
<option value="Chocolate" class="chocolate">Chocolate</option>
<option value="Classic Red" class="classic_red">Classic Red</option>
</select>
And here is my JSFiddle, though not sure how to demonstrate hashtags in JSFiddle.
https://jsfiddle.net/liquilife/n9r6af7e/1/
This has been resolved. And I've marked the answer as complete. The final code which works is below:
$( document ).ready(function() {
window.addEventListener('hashchange', fn, false);
window.onload = fn; // fire on pageload
function fn() {
$("#select-two").val(window.location.hash.replace('#','')).trigger("change");
}
});
Since you're using jQuery you can use the .trigger(eventName) method to start a specific event on an element.
For instance you can both set the value and cause the event to fire like so:
$("#select-two").val(window.location.hash.replace('#','')).trigger("change");
You can use jQuery's change function to detect when the selected value of your select element changes and to execute code when that happens.
https://api.jquery.com/change

jquery change value of input created after page load

I simply need to change the value of the input field which is created on button click. I have tried the below but it gives me undefined error since the element was not there when the page loaded. any ideas?
$('#test').val("test");
I use the below code for click event but I have no idea how to do the same thing for the above one too
$('body').on("click", ".btnx", function() {
//do something
});
$('#test').click(function(){
//code here
});
$('#test').empty();
$('#test').append('test');
There isn't anything like delegated events when you want to set the value of an input that is added out of your control, because there is no event to wait for.
You can wait for the element to come into existance, and set the value when it's there:
var handle = window.setInterval(function(){
var i = $('#test');
if (i.length) {
i.val('test');
window.clearInterval(handle);
}
}, 100);
The interval 100 means that it checks ten times per second, so it may be as long as 1/10th of a second after the element is created that the value is changed. You can adjust the value depending on how fast you need the value to be set, and how much overhead you can allow.

Detect IF hovering over element with jQuery

I'm not looking for an action to call when hovering, but instead a way to tell if an element is being hovered over currently. For instance:
$('#elem').mouseIsOver(); // returns true or false
Is there a jQuery method that accomplishes this?
Original (And Correct) Answer:
You can use is() and check for the selector :hover.
var isHovered = $('#elem').is(":hover"); // returns true or false
Example: http://jsfiddle.net/Meligy/2kyaJ/3/
(This only works when the selector matches ONE element max. See Edit 3 for more)
.
Edit 1 (June 29, 2013): (Applicable to jQuery 1.9.x only, as it works with 1.10+, see next Edit 2)
This answer was the best solution at the time the question was answered. This ':hover' selector was removed with the .hover() method removal in jQuery 1.9.x.
Interestingly a recent answer by "allicarn" shows it's possible to use :hover as CSS selector (vs. Sizzle) when you prefix it with a selector $($(this).selector + ":hover").length > 0, and it seems to work!
Also, hoverIntent plugin mentioned in a another answer looks very nice as well.
Edit 2 (September 21, 2013): .is(":hover") works
Based on another comment I have noticed that the original way I posted, .is(":hover"), actually still works in jQuery, so.
It worked in jQuery 1.7.x.
It stopped working in 1.9.1, when someone reported it to me, and we all thought it was related to jQuery removing the hover alias for event handling in that version.
It worked again in jQuery 1.10.1 and 2.0.2 (maybe 2.0.x), which suggests that the failure in 1.9.x was a bug or so not an intentional behaviour as we thought in the previous point.
If you want to test this in a particular jQuery version, just open the JSFidlle example at the beginning of this answer, change to the desired jQuery version and click "Run". If the colour changes on hover, it works.
.
Edit 3 (March 9, 2014): It only works when the jQuery sequence contains a single element
As shown by #Wilmer in the comments, he has a fiddle which doesn't even work against jQuery versions I and others here tested it against. When I tried to find what's special about his case I noticed that he was trying to check multiple elements at a time. This was throwing Uncaught Error: Syntax error, unrecognized expression: unsupported pseudo: hover.
So, working with his fiddle, this does NOT work:
var isHovered = !!$('#up, #down').filter(":hover").length;
While this DOES work:
var isHovered = !!$('#up,#down').
filter(function() { return $(this).is(":hover"); }).length;
It also works with jQuery sequences that contain a single element, like if the original selector matched only one element, or if you called .first() on the results, etc.
This is also referenced at my JavaScript + Web Dev Tips & Resources Newsletter.
Use:
var hovered = $("#parent").find("#element:hover").length;
jQuery 1.9+
It does not work in jQuery 1.9. Made this plugin based on user2444818's answer.
jQuery.fn.mouseIsOver = function () {
return $(this).parent().find($(this).selector + ":hover").length > 0;
};
http://jsfiddle.net/Wp2v4/1/
The accepted answer didn't work for me on JQuery 2.x
.is(":hover") returns false on every call.
I ended up with a pretty simple solution that works:
function isHovered(selector) {
return $(selector+":hover").length > 0
}
Set a flag on hover:
var over = false;
$('#elem').hover(function() {
over = true;
},
function () {
over = false;
});
Then just check your flag.
Couple updates to add after working on this subject for a while:
all solutions with .is(":hover") break on jQuery 1.9.1
The most likely reason to check if the mouse is still over an element is to attempt to prevent events firing over each other. For example, we were having issues with our mouseleave being triggered and completed before our mouseenter event even completed. Of course this was because of a quick mouse movement.
We used hoverIntent https://github.com/briancherne/jquery-hoverIntent to solve the issue for us. Essentially it triggers if the mouse movement is more deliberate. (one thing to note is that it will trigger on both mouse entering an element and leaving - if you only want to use one pass the constructor an empty function )
You can filter your elment from all hovered elements.
Problematic code:
element.filter(':hover')
Save code:
jQuery(':hover').filter(element)
To return boolean:
jQuery(':hover').filter(element).length===0
Expanding on #Mohamed's answer. You could use a little encapsulation
Like this:
jQuery.fn.mouseIsOver = function () {
if($(this[0]).is(":hover"))
{
return true;
}
return false;
};
Use it like:
$("#elem").mouseIsOver();//returns true or false
Forked the fiddle:
http://jsfiddle.net/cgWdF/1/
I like the first response, but for me it's weird. When attempting to check just after page load for the mouse, I have to put in at least a 500 millisecond delay for it to work:
$(window).on('load', function() {
setTimeout(function() {
$('img:hover').fadeOut().fadeIn();
}, 500);
});
http://codepen.io/molokoloco/pen/Grvkx/
https://api.jquery.com/hover/
Asynchronous function in line 38:
$( ".class#id" ).hover(function() {
Your javascript
});
Setting a flag per kinakuta's answer seems reasonable, you can put a listener on the body so you can check if any element is being hovered over at a particular instant.
However, how do you want to deal with child nodes? You should perhaps check if the element is an ancestor of the currently hovered element.
<script>
var isOver = (function() {
var overElement;
return {
// Set the "over" element
set: function(e) {
overElement = e.target || e.srcElement;
},
// Return the current "over" element
get: function() {
return overElement;
},
// Check if element is the current "over" element
check: function(element) {
return element == overElement;
},
// Check if element is, or an ancestor of, the
// current "over" element
checkAll: function(element) {
while (overElement.parentNode) {
if (element == overElement) return true;
overElement = overElement.parentNode;
}
return false;
}
};
}());
// Check every second if p0 is being hovered over
window.setInterval( function() {
var el = document.getElementById('p0');
document.getElementById('msg').innerHTML = isOver.checkAll(el);
}, 1000);
</script>
<body onmouseover="isOver.set(event);">
<div>Here is a div
<p id="p0">Here is a p in the div<span> here is a span in the p</span> foo bar </p>
</div>
<div id="msg"></div>
</body>

jQuery: Firefox focusout Event

I've got two input boxes in a div, I want to hide that div on the focusOut of the inputs, but only if both of them do not have focus.
This is a common Firefox problem (some call it adhering to standard), but the document body steals focus between.
HTML
<div id="baz">
<input type="text" id="foo" name="foo" />
<input type="text" id="bar" name="bar" />
</div>
jQuery
// jQuery Example
jQuery(":input").focusout(function(){
// Don't do anything if one of the input boxes has focus
if( jQuery(":input").is( jQuery(document.activeElement) ){ return; }
// Hide the container if one of the inputs loose focus
jQuery(this).parents("div").css("display","none");
}
Though this is a common bug, I forget how I solved it in the past. I think it had something to do with setting a timeout, or doing a screen refresh, before checking for the activeElement.
jsFiddle Example
jsFiddle Updated (FF4 Same Problem)
Demo
jQuery(":input").focusout(function(){
var elem = jQuery(this).parent("div");
window.setTimeout(function(){
// Don't do anything if one of the input boxes has focus
if( jQuery(":input").is( jQuery(document.activeElement) )){ return; }
// Hide the container if one of the inputs loose focus
elem.hide();
}, 0);
})
Demo
jQuery(document).ready(function () {
var timeoutID;
jQuery(":input").focus(function () {
window.clearTimeout(timeoutID);
}).focusout(function () {
timeoutID = window.setTimeout(function () {
jQuery("#baz").hide();
}, 0);
});
});
I think amit_g's solution was almost there. I vaguely remember that I've went about this in two ways:
compare the inputs to the activeElement (the method showed above)
setting/clearing a "focus" class on the element for the respective events
I think both methods required using setTimeout, since Firefox has a delayed trigger, which we need to force. While I've heard FF is adhering to standards here, I personally think that standard needs to be amended.
So in addition to adding the timed function call, it also needed to be cleared if the other "acceptable" element gained focus. The following is not production code but it does show it does serve as an example:
Example Solution
Example Solution (Even Better) - set $debug to false
Example Solution (Localized Blocks) - removed debugging clutter

Using jQuery to test if an input has focus

On the front page of a site I am building, several <div>s use the CSS :hover pseudo-class to add a border when the mouse is over them. One of the <div>s contains a <form> which, using jQuery, will keep the border if an input within it has focus. This works perfectly except that IE6 does not support :hover on any elements other than <a>s. So, for this browser only we are using jQuery to mimic CSS :hover using the $(#element).hover() method. The only problem is, now that jQuery handles both the form focus() and hover(), when an input has focus then the user moves the mouse in and out, the border goes away.
I was thinking we could use some kind of conditional to stop this behavior. For instance, if we tested on mouse out if any of the inputs had focus, we could stop the border from going away. AFAIK, there is no :focus selector in jQuery, so I'm not sure how to make this happen. Any ideas?
jQuery 1.6+
jQuery added a :focus selector so we no longer need to add it ourselves. Just use $("..").is(":focus")
jQuery 1.5 and below
Edit: As times change, we find better methods for testing focus, the new favorite is this gist from Ben Alman:
jQuery.expr[':'].focus = function( elem ) {
return elem === document.activeElement && ( elem.type || elem.href );
};
Quoted from Mathias Bynens here:
Note that the (elem.type || elem.href) test was added to filter out false positives like body. This way, we make sure to filter out all elements except form controls and hyperlinks.
You're defining a new selector. See Plugins/Authoring. Then you can do:
if ($("...").is(":focus")) {
...
}
or:
$("input:focus").doStuff();
Any jQuery
If you just want to figure out which element has focus, you can use
$(document.activeElement)
If you aren't sure if the version will be 1.6 or lower, you can add the :focus selector if it is missing:
(function ( $ ) {
var filters = $.expr[":"];
if ( !filters.focus ) {
filters.focus = function( elem ) {
return elem === document.activeElement && ( elem.type || elem.href );
};
}
})( jQuery );
CSS:
.focus {
border-color:red;
}
JQuery:
$(document).ready(function() {
$('input').blur(function() {
$('input').removeClass("focus");
})
.focus(function() {
$(this).addClass("focus")
});
});
Here’s a more robust answer than the currently accepted one:
jQuery.expr[':'].focus = function(elem) {
return elem === document.activeElement && (elem.type || elem.href);
};
Note that the (elem.type || elem.href) test was added to filter out false positives like body. This way, we make sure to filter out all elements except form controls and hyperlinks.
(Taken from this gist by Ben Alman.)
April 2015 Update
Since this question has been around a while, and some new conventions have come into play, I feel that I should mention the .live method has been depreciated.
In its place, the .on method has now been introduced.
Their documentation is quite useful in explaining how it works;
The .on() method attaches event handlers to the currently selected set
of elements in the jQuery object. As of jQuery 1.7, the .on() method
provides all functionality required for attaching event handlers. For
help in converting from older jQuery event methods, see .bind(),
.delegate(), and .live().
So, in order for you to target the 'input focused' event, you can use this in a script. Something like:
$('input').on("focus", function(){
//do some stuff
});
This is quite robust and even allows you to use the TAB key as well.
I'm not entirely sure what you're after but this sounds like it can be achieved by storing the state of the input elements (or the div?) as a variable:
$('div').each(function(){
var childInputHasFocus = false;
$(this).hover(function(){
if (childInputHasFocus) {
// do something
} else { }
}, function() {
if (childInputHasFocus) {
// do something
} else { }
});
$('input', this)
.focus(function(){
childInputHasFocus = true;
})
.blur(function(){
childInputHasFocus = false;
});
});
An alternative to using classes to mark the state of an element is the internal data store functionality.
P.S.: You are able to store booleans and whatever you desire using the data() function. It's not just about strings :)
$("...").mouseover(function ()
{
// store state on element
}).mouseout(function ()
{
// remove stored state on element
});
And then it's just a matter of accessing the state of elements.
if anyone cares there is a much better way to capture focus now, $(foo).focus(...)
http://api.jquery.com/focus/
Have you thought about using mouseOver and mouseOut to simulate this. Also look into mouseEnter and mouseLeave
Keep track of both states (hovered, focused) as true/false flags, and whenever one changes, run a function that removes border if both are false, otherwise shows border.
So: onfocus sets focused = true, onblur sets focused = false. onmouseover sets hovered = true, onmouseout sets hovered = false. After each of these events run a function that adds/removes border.
As far as I know, you can't ask the browser if any input on the screen has focus, you have to set up some sort of focus tracking.
I usually have a variable called "noFocus" and set it to true. Then I add a focus event to all inputs that makes noFocus false. Then I add a blur event to all inputs that set noFocus back to true.
I have a MooTools class that handles this quite easily, I'm sure you could create a jquery plugin to do the same.
Once that's created, you could do check noFocus before doing any border swapping.
There is no :focus, but there is :selected
http://docs.jquery.com/Selectors/selected
but if you want to change how things look based on what is selected you should probably be working with the blur events.
http://docs.jquery.com/Events/blur
There is a plugin to check if an element is focused: http://plugins.jquery.com/project/focused
$('input').each(function(){
if ($(this) == $.focused()) {
$(this).addClass('focused');
}
})
I had a .live("focus") event set to select() (highlight) the contents of a text input so that the user wouldn't have to select it before typing a new value.
$(formObj).select();
Because of quirks between different browsers, the select would sometimes be superseded by the click that caused it, and it would deselect the contents right after in favor of placing the cursor within the text field (worked mostly ok in FF but failed in IE)
I thought I could solve this by putting a slight delay on the select...
setTimeout(function(){$(formObj).select();},200);
This worked fine and the select would persist, but a funny problem arose.. If you tabbed from one field to the next, the focus would switch to the next field before the select took place. Since select steals focus, the focus would then go back and trigger a new "focus" event. This ended up in a cascade of input selects dancing all over the screen.
A workable solution would be to check that the field still has focus before executing the select(), but as mentioned, there's no simple way to check... I ended up just dispensing with the whole auto highlight, rather than turning what should be a single jQuery select() call into a huge function laden with subroutines...
What I wound up doing is creating an arbitrary class called .elementhasfocus which is added and removed within the jQuery focus() function. When the hover() function runs on mouse out, it checks for .elementhasfocus:
if(!$("#quotebox").is(".boxhasfocus")) $(this).removeClass("box_border");
So if it doesn't have that class (read: no elements within the div have focus) the border is removed. Otherwise, nothing happens.
Simple
<input type="text" />
<script>
$("input").focusin(function() {
alert("I am in Focus");
});
</script>

Categories