I'm having trouble finding a solution to this via google but I would have assumed it would be quite a common problem. I have a div which I have applied an onmouseout event handler to (the handler is used to roll a menu up using jquerys "slideup" function, as I would like the menu to be hidden when the mouse leaves). Problem is that the child elements of that div also cause the handler to fire (I accept that this is by design due to the nature of the bubbling event model). Now what I would like to know is what is the best way to ignore these events that are triggered by the divs children and only roll the menu up when the mouse leaves the div the event is applied to.
Thanks
What you are looking for is mouseenter and mouseleave.
A good example can be found at this link (they have compared both mouseenter and mouseover)
http://docs.jquery.com/Events/mouseover
A blog entry
http://blogs.oracle.com/greimer/entry/mouse_over_out_versus_mouse
You might want to attempt cancelling the event bubbling or propagation. Quirksmode.org has a handy section explaining how to turn off bubbling or propagation in both the models.
Since JQuery presents the W3C standards to developers, you will not need to set the cancelbubble property. Calling stopPropagation() method will be enough.
Use the "mouseenter" and "mouseleave" on the parent div instead - the child elements will not effect the "mouseleave"
document.getElementById('Main_Menu_Container_Div').addEventListener('mouseenter',function(){
// do something like your 'slideup' or what ever you want.
});
"Event bubbling" as it is known, is the problem - "event on element2 takes precedence. This is called event bubbling". http://www.quirksmode.org/js/events_order.html
Use Example:
<style>
.Child_Div_Button{
float:left;
cursor:pointer;
height:100px;
width:100px;
background-color:#CCC;
border:#000 thin solid;
margin:2px;
padding:2px;
}
.Child_Div_Button:hover{
background-color:#FFF;
}
</style>
</head>
<body>
<div id="Parent_Div_Container" style="height:300px; width:300px; border:#333 thin solid; background-color:#D2FFFF;">
Parent Div
<div id="button_container">
<div class="Child_Div_Button">
Button 1 Child Div
</div>
<div class="Child_Div_Button">
Button 2 Child Div
</div>
</div>
</div>
<script type="text/javascript">
document.getElementById('button_container').style.display = 'none';// initiate
document.getElementById('Parent_Div_Container').addEventListener('mouseenter',function(){
document.getElementById('button_container').style.display = 'block';
});
document.getElementById('Parent_Div_Container').addEventListener('mouseleave',function(){
document.getElementById('button_container').style.display = 'none';
});
</script>
Seems to work in latest Firefox WITHOUT the need for JQUERY - But Chrome, IE and Safari, all seem to need the jquery library for this to work. Is that to say that mozila now fully supports the use of mouseenter and mouseleave?!?! If so .. YAY! for the browser that actually does things to help developers : )
Simon you can check who has trigged the event using jquery Event.target property.
No, it's not by design, you've accidentally applied your 'onmouseout' to too many divs. You only want to apply it to one.
Related
Problem: Firefox loses the first click event when a textarea has the following CSS:
textarea:focus {
resize: vertical;
}
See demo: http://jsbin.com/wuxomaneba/edit?html,css,output
The solution to this is simple - remove the :focus selector.
However I'd like to know why this happens and are there any other css rules or situations where this can occur.
While this does look like a bug (thanks for filing it!), generally a click event is dispatched to the deepest element that observed both the mousedown and mouseup events. So you can similarly "break" the click event by moving the textarea on :focus (e.g. position:absolute; top: xxx) - this is because the order of events is mousedown->focus (updates the web page)->mouseup->click.
The resize property controls "anonymous content" that's not visible to the web page, but used by the browser to implement the additional UI for the user's benefit. My guess is that changes to this content interfere with click event detection, but without looking at this in a debug build it's impossible to say for sure.
function logEvent(ev) {console.log(ev.type, window.getComputedStyle(document.querySelector("textarea")).resize)}
document.querySelector("textarea").addEventListener("mousedown", logEvent, false);
document.querySelector("textarea").addEventListener("focus", logEvent, false);
document.querySelector("textarea").addEventListener("mouseup", logEvent, false);
document.querySelector("textarea").addEventListener("click", logEvent, true);
textarea:focus{
position:absolute; top: 500px;
/*resize:vertical;*/
}
<textarea>click me</textarea>
This is because when you click on the resize button, you don't focus to the textarea but to the resize button on Firefox. I do not know if this is a bug or not, but it looks like it was intended. Removing :focus removes the requirement of focusing on the textarea, therefore it applies when you hold the resize button, which only goes vertically.
The simplest way is to use jQuery focus. For me it is more simple yet effective and applicable to all kind of browsers.
If you want it focus upon loading the page.
$( document ).ready(function() {
$('#txtId').focus();
});
I would like to design something similar to what can be seen on http://www.thedana.com/ by the "Check availability" button - I've used the jquery.js file from w3school.com and got the following so far: http://quaaoutlodge.com/drupal-7.14/ (Book Now tab). Now as you realize, it is very touchy and fades out sometimes when it shouldn't (when the cursor is still in the middle of the field) how can I make this nicer, more user friendly?
Thanks!
Ron
Update:
I tried to implement that but it doesn't quite work as I would like to show my "fade" div upon hovering over "book" and keep it up as the cursor moves down, over "fade" how do I accomplish this?
Url:http://quaaoutlodge.com/drupal-7.14/
Put the div#fade inside of the div#book, that will solve half of your problems. You will have to adapt the CSS as well for this change.
Another very important point to learners is that jQuery provides unobtrusive cross-browser event listeners attaching. That means, inline JS in the html as onmouseenter="handler()" is not just unnecessary and technically ugly - mixed structure with behavior -, it also pollutes the global scope with function names.
That's one of the reasons people advertise against W3School.
But back on topic here's a solution using the DOM Ready handler and a hover one:
Fiddle
HTML
<div id="book">
Book Now
<div id="fade">TEST</div>
</div>
JS
$(function() {
var fade = $('#fade');
$('#book').hover(function() {
fade.fadeIn();
}, function() {
fade.fadeOut();
});
});
Again, you will have to rework the CSS removing the position:absolute and margins from #fade.
Can you try with jquery's .mouseleave instead of the generic onmouseout?
http://api.jquery.com/mouseleave/
"The mouseleave event differs from mouseout in the way it handles event bubbling. If mouseout were used in this example, then when the mouse pointer moved out of the Inner element, the handler would be triggered. This is usually undesirable behavior. The mouseleave event, on the other hand, only triggers its handler when the mouse leaves the element it is bound to, not a descendant. So in this example, the handler is triggered when the mouse leaves the Outer element, but not the Inner element."
I have a page that need to toggle the visibility of a div at regular interval. The issue is that the click events related to one of the parent element are often not called. If I stop the visibility toggle or if I slow it down (for example 300ms instead of 100ms) the click events are fired normally.
I have created a short example illustrating this issue.
You can test it here: http://threeds.me/0xC0DE/
Clicking the blue/red square should in theory fire the click event. When there is no animation (default behaviour here) clicking the blue square will always fire the onclick event. If you click on 'play/pause' the visibility of the red square will start to toggle every 100ms. When the animation is playing the click event is not call everytime you click on the square.
I would suspect that changing the visibility is somehow messing up with the DOM which as a result stop events for some milliseconds. I also tried to toggle the css visibility property to minimize the impact on the page but it has the same result.
But it's not only events. If I encapsulate the whole container in an tag, clicking the element will not be always taking into account by the browser. So it's like that changing the visibility of a child element will make a parent blind for (quite) some time which I find really strange.
This issue is consistent with Firefox, Chrome and Opera (all on mac, cannot test ie) so it means there is something I don't get. So even if I don't get a solution, I would like to understand what is the problem.
Here the source for your immediate reference
<!DOCTYPE html>
<html>
<head><title>Wiggle problem</title>
<style>
#dback {
width: 200px;
height: 200px;
background-color: red;
}
#dfront {
width: 200px;
height: 200px;
background-color: blue;
}
</style>
<script type="text/javascript">
var run = false;
function playpause() {
if ( run ) {
run = false;
} else {
run = true;
update();
}
}
function update() {
if ( run==false ) {
return;
}
var el = document.getElementById('dfront');
if ( el.style.display != 'none' ) {
el.style.display = 'none';
}
else {
el.style.display = '';
}
setTimeout("update();", 100);
}
</script>
</head>
<body>
play/pause
<div id="container" onclick="d=new Date();t=d.getTime();document.getElementById('info').innerText='click '+t;">
<div id="dback">
<div id="dfront"></div>
</div>
</div>
<span id="info"></span>
</body>
</html>
That is really weird! However, I made some tests and fiddled with your code a bit, and now I think it has nothing to do with bubbling (you can see on my test that clicks on elements with visibility: hidden bubble just fine).
Here is what I think could be going on: since your timer interval is so short, there is not enough time for an actual click to be registered – a click being a mousedown event, followed by a mouseup event, on the same element. What happens in your case is that mouseup is frequently being fired on the other element, not the same one that fired mousedown, and thus there is no click event. See the second link above, where I reduced the interval to 1 sec, and try to click on the blue square, and release the mouse button on the red square (or vice-versa). Nothing happens. I may be completely wrong, but that looks plausible.
I know this is not a solution, but you said:
So even if I don't get a solution, I would like to understand what is the problem.
I hope this can help you find one!
Last but not least, a couple of side notes on your code:
The way you're calling setTimeout (passing a string) is not recommended, because it will force the use of eval internally, and eval should be avoided as much as possible. Instead of passing the string with the function call code, just pass the function itself:
setTimeout(update, 100);
It's considered a best practice today to use addEventListener (or attachEvent for IE) to bind an event to an element, instead of using inline events like your onclick="...". That has several advantages, like helping separate behavior, structure and layout, and making the event object automatically available to the event handler (as the first parameter to the handler function).
Acctually, when "dfront" is visible, its hovering over "container", and when you make a click, event goes to "dfront". but there is no onclick event, for "dfront" element.
Onclick event of "container" is not propagating on child elements - its normal, you can workaround it by using jquery it has "event propagation" option for events.
Or just set onclick event for "dfront".
Also you can create transparent layer over "container" and "dfront" and bind event to it.
Or, make onmouseclick event on window object, which will find out, if mouse position is over "dfront" by checking their coordinates and if true then event handler will be fired.
I noticed that in Webkit the <button> element does not fire the onclick event when the mouse is moved from/to child elements of the button during the click. With other words: when the mousedown and mouseup events do not happen on the same element - even if both are children of the button.
The same happens when clicking/releasing on/out of the pixels of the button text.
To clarify I made a testcase: http://jsfiddle.net/gx9B3/
It works fine in FireFox. Fails in Chrome 15 and QtWebkit 4.7.1
Is there a way around this? I need a solution specifically for Webkit because my project is targeted to this browser only.
Solution
I could solve this problem based on the method suggested by Jan Kuča (the solution I accepted). Some additional tweaks were necessary, especially introducing a timer to avoid double clicks. Have a look at my fully working solution at JSFiddle:
http://jsfiddle.net/mwFQq/
You could set up a mousedown listener on document.body (to fix the problem on the whole page). You would check if the mousedown event originated from an HTMLButtonElement (or from any of its child elements) and if it did, you set up a mouseup listener (on the button so it does not have to bubble too much) that will check the target property of the mouseup event. If it is contained in the button and is different from the target of the mousedown event, you fire a click event like this:
var e = document.createEvent('Events');
e.initEvent('click', true, true);
button.dispatchEvent(e);
(Do this only for WebKit-based browsers so that you don't get multiple click events in other browsers. Or you could call the preventDefault method of the mousedown event as it should also prevent firing the click event.)
You could try adding this CSS style:
button * {
pointer-events: none;
}
Child elements will then ignore mouse events and the click will come from the button element itself. Here's an example http://jsfiddle.net/Tetaxa/gx9B3/2/
You can also solve it by pure CSS trick. Just place pseudo element over <button> to cover text:
button {
position:relative;
}
button:after {
position:absolute;
top:0;
left:0;
right:0;
bottom:0;
content:'';
}
Is there any way that I can call a JavaScript function via css?
For example, from this :hover style:
.first-nav li a:hover,
.first-nav li.hover a {
margin:-3px 0 -1px;
height:30px;
position:relative;
background:url(../images/nav-hover.jpg) no-repeat;
}
The JavaScript function I want to call is on an anchor :hover.
No, you can't trigger JavaScript from CSS directly.
What you can do is use CSS selectors to find the elements you want to watch in this way, and then watch for mouse events. The standard events are mouseover and mouseout, but they can be a bit tricky to work with because they bubble (you get mouseout, for instance, whenever the mouse leaves any descendant element). With appropriate logic, though, they're not to bad to work with, and in fact if you have lots of these, you probably want to use mouseover and mouseout rather than the alternative below because you can set them on just a parent container and then work out which descendant element is involved, which can be simpler in some cases (and more complicated in others).
IE provides mouseenter and mouseleave which are much easier to work with because they don't bubble, but (of course) IE-specific. These are so handy that frameworks are starting to support them even in browsers that don't; Prototype and jQuery provide them, for instance, and I wouldn't be too surprised if some other frameworks do as well. jQuery also provides the handy hover function, which would be very close to what you want:
// jQuery
$(".first-nav li a").hover(
function(event) {
// The mouse has entered the element, can reference the element via 'this'
},
function (event) {
// The mouse has left the element, can reference the element via 'this'
}
);
...which is really just a shortcut for setting up mouseenter and mouseleave handlers, but still, wonderfully concise.
In Prototype it's quite similar:
// Prototype
$$(".first-nav li a")
.invoke("observe", "mouseenter", function(event) {
// The mouse has entered the element, can reference the element via 'this'
})
.invoke("observe", "mouseleave", function(event) {
// The mouse has left the element, can reference the element via 'this'
});
(OT: In both cases, I've used anonymous inline function expressions just to avoid giving the impression you have to use named functions. I always recommend using named functions in production code, though.)
No.
(Well, Microsoft Expressions and Mozilla Bindings might allow it, but both are proprietary and should be avoided)
Assign your event handlers from JavaScript. Libraries such as YUI and jQuery allow you to pick elements to apply them to using CSS selectors. Event delegation allows you to handle events on elements without having to assign to each one explicitly (which is handy if you are adding them to the document after it loads).
You can call it from javascript(it does the same thing). Below is the code on how to do it on JS:
<script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.min.js"></script>
<script type="text/javascript">
$(document).ready(function(){
$("a").hover(function(){
myFunctionInvoke();
});
});
</script>
or if you have particular anchor in mind just change the selector
Because it's more logical to do it from CSS.
If one wants to make links click on hover, it's an aesthetic quality and should be handled with CSS. For example:
#header_menu li a:hover{
color:white;
js:click();
}
It's both an aesthetic quality and, as such, it should be handled with CSS and a functional quality which should, as such, be handled with html and javascript.
And there is a very simple way to call a function on page load from within html:
<body onload="myFunction()">
Actually. Yes you can. Just use javascript: in the background-url like this:
<STYLE type="text/css">BODY{background:url("javascript:yourFunction();")}</STYLE>
Not entirely sure if this will work though.
Cheers!