jQuery 1.8: unsupported pseudo: hover - javascript

The following code raises the error unsupported pseudo: hover on jQuery 1.8, while it works perfect on jQuery 1.7.2:
if(!$(this).parent().find('ul').first().is(':hover')) {
$(this).parent().parent().removeClass('open');
}
Does anyone know what's going on?

Unfortunately, while we all wish that our code were future proof, your $('foo').on( 'hover, ... function(){ //do stuff } code is deprecated in jQuery 1.8. I wish I had better news for you, but your code is broken because of a core change to jQuery 1.8. You now have to use the syntax
$('.selector').on( 'mouseenter mouseleave', function() {
$(this).toggleClass('hover');
}
);
if(!$(this).parent().find('ul').first().hasClass('hover')) {
$(this).parent().parent().removeClass('open');
}
Wish I had better news for you, but deprecation happens :/ ... jQuery 1.8 doesn't like your shortcut and they've deprecated the hover event handler from .on() and also the pseudo-selector :hover, so it can't be used that way any more.

Old question, but for anyone googling:
A workaround for this is to go the other way round:
$(":focus, :active").filter($(".your-element"));
…because .filter() also accepts jQuery objects, this will match any elements with the pseudos :focus and :active that also have the class .your-element.
In other words, if .your-element isn't hovered or active, this selection matches no elements.

weird - for me, .is(":hover") is still working in 1.8, but broken in 1.9.1.
Anyway, here is a fix
function mouseIsOverWorkaround(what){
var temp = $(what).parent().find(":hover");
return temp.length == 1 && temp[0] == what;
}
then call above function on the "naked" (non jQuery-wrapped) element. In your case,
if(!mouseIsOverWorkaround($(this).parent().find('ul').first()[0]) {
$(this).parent().parent().removeClass('open');
}
(don't forget the [0])
the above-mentioned (comment to orig question) fiddle http://jsfiddle.net/nnnnnn/Tm77a/ does not work in jQuery 1.9.1
fiddle with this one http://jsfiddle.net/mathheadinclouds/BxL4w/

Related

JQuery / Live is deprecated, well okay… But is not replaced

On is not working as a replacement for live; as the new ON is NOT working for future elements. No problems in my implementations; I'm used to use live and I definitely know when something works or not with jquery.
haml part :
.field
%label Select a file
= file_field_tag 'post[image]', :class => :dashed
%span.adder + add another file
coffe part :
$("span.adder").on "click", (e) ->
new_field = $(this).closest(".field").clone()
$(new_field).insertAfter( $(this).closest(".field") )
Why the new span.adder added does not have the jquery behaviour attached to their class ?
Something like this shoudl work in that case.
Why the JQuery guys did remove it ?
I don't get it.
UPDATE
$("span.adder").on("click", function(){ });
Will not work as live.
It has to be
$(document).on("click", "span.adder", function(){ });
(thanks for everyone's answers.)
To work with future elements you must use on document like this
$(document).on('click', 'span.adder', function(){
//Code here
});
Before .on() ever came around, .live() was already considered an inefficient way to handle event binding, Because of that for future use you have to use .on()
e.g:-
$(document).on('click', '#yourElement', function() {
// your functions here
});
There is a better explanation here
It is a replacement. The direct translation would be:
$(document).on('click', '.my-selector', function() {});
They deprecated and remove it because they had better implementation. You see the documentation of .on()
$(ancestor).on(event, element, function);
You should use that as ancestor which is near to that element. There are some performance issues.
Upgrade jQuery version also.
On works asdelegate` used to do, not exactly as .live; you have to use it on a parent and then specify the event and the children that triggers it; something like.
$(window).on("click", ".button", function(){
alert("You clicked the button... and I hate alerts");
});

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 - why do i need live() in this situation?

I have a somewhat odd situation. I understand the premise of the live() and bind() functions, yet in a situation where i believe i dont need them, i seemingly do. I will explain.
I made an autosuggest in jquery. I included autosuggest.js at the top of my page. I then have an input field.
The basis of the JS works around:
$(".autosuggest").keyup(function()
{
}
This works - on keyup, my function executes etc as expected - i dont need to use live() or bind() as the input field is on the page from the get go...
Now.. I have also made a 'star rater' esque script.
I have various elements (which are styled), and on hover they are restyled...
$('.rating li').mouseover(function() {
}
does NOT work, YET
$('.rating li').live('mouseover',function() {
}
DOES.
Why do i need to use 'live' in this situation, when i dont in the case of the autosuggest?
Thanks
The only thing I can imagine that would cause this is a lack of a domready event. This should work:
$(function () {
$('.rating li').mouseover(function() {
}
});
the .ratings li isn't parsed yet when you have .mouseover() not working.
You can wrap it in $(document).ready(function() {...}); or use .live() (which creates the binding for any currently parsed at that point in the script and any elements added in the future).
Did you put $('.rating li').mouseover(function() {
}
in $(document).ready(function() {....} ?
Even if you include a .js file, if the elements in the page ('rating li') are not loaded, the bind will not be made.
Without seeing more of you code, it's difficult to say for sure. But my guess would be that your script is running before the pageload completes. try wrapping your bindings (and anything else that depends on particular dom elements to exist) with a call to $(document).ready(...).
something like this:
$(document).ready( function() {
$('.rating li').mouseover(function() {
// whatever
});
$(".autosuggest").keyup(function() {
// whatever else
});
});
If that's not it, then post more of your code, and we'll dig in further.
good luck.

:hover selector doesn't work with jQuery 1.4

Googled about it - found nothing.
I'm talking about CSS :hover, not jQuery .hover().
So, the code:
$('#something a:hover').css({'something': 'thomesing'});
works fine with 1.3, but not with 1.4. How to fix it?
Follow the rules
This is a superb example of why we must always code according to the documentation, and not according to the possibilities. Hacks, or mere oversights like this, will eventually be weeded out.
The proper jQuery (plain css is better) way to do this follows:
$("#something a").hover(
function() {
// $(this).addClass("hovered");
$(this).css("color", "red");
},
function() {
// $(this).removeClass("hovered");
$(this).css("color", "black");
}
);
The $.fn.hover method takes up to two arguments and serves as syntactic sugar for more explicit pointer (mouse) events. In fact, the hover method in jQuery 2.1.0 was nothing but this:
function( fnOver, fnOut ) {
return this.mouseenter( fnOver ).mouseleave( fnOut || fnOver );
}
Understand your code, and be concise
As you can see, the fnOver function is called when you enter the element, and again when you exit (if no other method is provided). With this understanding, we can setup simpler instructions:
$("#something a").hover(function () {
$(this).toggleClass("hovered");
});
Native almost always wins
Ultimately, vanilla CSS is the way to go. The :hover pseudo-class has been around for a long time, and works with targeting not only the element to which it belongs, but nested elements as well:
#something a:hover {
background: red;
}
#something a:hover .icon {
animation: 2s rotate ease-out;
}
With something as broadly-supported as :hover, I can think of no good reason to avoid it.
:hover is not a documented pseudoclass selector.
Try this:
$('#something a').hover(function(){
$(this).css({'something': 'thomesing'});
},
function(){
$(this).css({'something': 'previous'});
});
Although, you'd be better to use CSS classes:
$('#something a').hover(function(){
$(this).toggleClass("over").toggleClass("out");
},
function(){
$(this).toggleClass("over").toggleClass("out");
});
http://docs.jquery.com/Events/hover
EDIT:
In respose to BlueRaja's comment below, the following would be more suitable:
$('#something a').hover(function(){
$(this).addClass("over").removeClass("out");
},
function(){
$(this).removeClass("over").addClass("out");
});
hover changed in 1.4 and funny no one here seems to have bothered checking the jQuery docs...
$("#something a").hover(
function () {
$(this).toggleClass("active")
}
);
Change the colors via css.
Note:
Calling $(selector).hover(handlerInOut) is shorthand for:
$(selector).bind("mouseenter mouseleave",handlerInOut);
:hover is not supported in jQuery (see docs).
It doesn't really make sense either: jQuery selectors are used to select elements. What would ":hover" select?
I'm surprised it even works in 1.3
I don't think it does work in 1.3. As Philippe mentioned, it doesn't make sense.
:hover is an event, not an attribute. So I don't see how that selector could work.
You could either use the hover function as antpaw mentioned - http://docs.jquery.com/Events/hover#overout
or you could set a css style rule. e.g.
$('head').append("<style type='text/css'>#something:hover{foo: bar}</style>");
you can use .hover() function or even better plain css
To me, that selector doesn't make much sense, because it depends on an event by the user. Selectors are more about static content, where as the function hover() can track an event. The user would have to have his mouse on top of the content when you made the call.
There might be some cases that it would be useful, but in the case you mentioned, Jonathon Sampson has the right answer. Use $("#something a").hover(function() {$(this).css("something","thomesing");}); instead.
How jQuery works is that it parses selectors (whether css or regular ones) and then returns the jQuery object. As of today , jQuery doesn't support ':hover' selector.
It might work in Chrome or FF or Safari, but will definitely fail in IE6, 7 and 8.
Great workaround would be to either use jQuery's hover() method.
In more complex cases you want to register mouseenter and mouseleave event handlers on container that you want to select with ':hover', and add/remove '.hover' class.
Once the regular 'hover' class is there, you can easily access that container element from anywhere in the code using '#container.hover' selector.
Let me know if you need help coding this...

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