the mouseout event occur more than one time - javascript

Hi:
when I add a mouseout event to a parent element,it seems that all of its child are added this event also,it works well if the event is a mouse click and etc.
However for the mouseout event,this will cause some unexpected result.
Take a look at this example:
<html>
<head>
<script type="text/javascript">
function init(){
document.getElementById('par').onmouseout=function(){alert('mouse out')};
}
</script>
</head>
<body onload='init()'>
<div id="par" style="width:400px;height:300px">
<div style="background-color:red;width:100%;height:150px"></div>
<div style="background-color:black;width:100%;height:150px"></div>
</div>
</body>
</html>
please Move from the red div to the black div,then move out of the black div,then you will get two alert window,I just want one.
So how to fix it?

That's not possible using plain javascript without the mouseleave event, which, to my knowledge, is only supported by Internet Explorer.
Javascript toolkits may provide a solution, jQuery for instance emulates that event:
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.

Related

How to stop double-touching in iOS from scaling the entire page

I have a webapp with an inner-pane inside an outer-window.
The user can do various touch operations, e.g. zoom-in in the inner-pane via 2-finger pinch, without zooming-in the outer-window, touch move to pan the inner window etc..
On Chrome on Android, the app works as expected.
But Safari on iOS device (iPad), the entire window sometimes scales when quickly double-toching on the border-line of the inner window.
I found out that I can prevent this side effect by adding an event listener on the touchend event.
window.addEventListener('touchend', onTouchEnd5, {capture: false, passive: false});
and calling event.preventDefault() in the binded function.
async function onTouchEnd5( event ) {
console.log('BEG onTouchEnd5');
event.preventDefault();
};
But this causes another side effect where touch-clicks on buttons are not intercepted.
I tried adding eventlisteners on other events that are possibly trigerred by the default behavior, e.g. click, dblclick, touchcancel, fullscreenchange, fullscreenerror, resize, onscroll
The idea was to try and prevent the default behaviour for these events in case that the side effect is caused there.
(the rational was that iphone/ipad can trigger unexpected events).
From the listed events above, the event onscroll is trigerred.
In the binded function to this event, I added preventDefault():
function onScroll5( event ) {
console.log('BEG onScroll5');
event.preventDefault();
};
But the I can still cause the entire window to rescale by quickly double-touching on the border-line of the inner window.
How can I prevent the entire window from scaling in iOS when double touching?
Note:
The scaling of the entire window is the latest observation.
Before that, I found that the entire window scales when e.g. doing a twon-finger pinch in another section of the window.
The solution in this case, was to add preventDefault on another event listener binded function.
Given that there are multiple events in the app, a more general question is:
Is there a way to prevent the entire window from scaling alltogether, in eny event?
Thanks
I've found a bit of a hacky solution.
Make a page called /mobile, or use / and put all your content on a page called /maincontent and use that URL in the next step.
In that page, add an iframe, like this:
<iframe src='/ (or "maincontent")' style='width:100vw;height:100vh;top:0;left:0;position:fixed;border:none;' frameborder='0'></iframe>
I know it's a bit hacky, but it works for me on iOS 14.
I found out the solution.
I had the following DOM structure:
<body>
<div id="div1">
<div id="div2">
<div id="div3">
<canvas>...</canvas>
</div>
</div>
<div id="div4">
<div id="div5"><button></div>
</div>
</div>
</body>
I initially tried to add event.preventDefault() in onTouchStartDiv3(), which listens to events in the canvas element (the closest upstream element with event listener is div3).
This solved the problem of double-touch in the border but caused another problem:
onTouchMoveDiv3() was called immediately (without even moving the finger), which caused other side-effects. (I have some state machine in the level, that depends on the onTouchStartDiv3(), onTouchMoveDiv3(), onTouchEndDiv3()).
I then tried to add event listeners at the window/document levels (onTouchStartWindow(), onTouchStartDocument()) and call event.preventDefault() in them.
This again solved the problem of double-touch in the border but caused another problem:
The button (div5), stopped responding to touch events.
The reason was that, because there is no specific event listener on the button, the event was intercepted higher up, and default behaviour was applied.
Because the window/document event listener called event.preventDefault(), this behaviour was prevented (which stopped the button from responding to touch events).
Finally, I added event listener at the touched border level (div2).
Inside onTouchStartDiv2() I compare event.currentTarget (div2), to event.target where the event originated.
If the event.target is div2 then the event originated from clicking on the border, so I apply event.preventDefault() to prevent the side-effect of resizing the entire image on iOS.
If the event.target is not div2 then the event originated from clicking, e.g. in the canvas, so I do not apply event.preventDefault() to maintain the state machine.
With this logic, I solved the problem:
when touching the canvas element (div3 is the closest upstream element with event listener), the regular behaviour was applied.
when touching the border element (div2), event.preventDefault() was applied to the event listener, and prevent the default behaviour of resizing the entire window (which I wanted to disable).
when touching the button element (div5), the regular behaviour was applied so the button responded to touch events.

keep mouse over active if hovering over another overlapping element

I've got a DOM structure like the one below. These to elements are overlaping. On hover, video start to play. Unfortunately, when I hover over .showsOnHover, mouseover and mouseout repeatedly fire one after another making .showsOnHover blink and video stutter.
What should I do to instruct browser to treat hovering over .showsOnHover as one continuous hover?
.html
<video (mouseover)="mouseover()" (mouseout)="mouseout()"></video>
<div [hidden]="!hovering" class="showsOnHover"></div>
.ts
mouseover(e){
this.hovering = true;
this.video.play();
}
mouseout(e){
this.hovering = false;
this.video.stop();
}
The issue is that when showsOnHover is shown, it covers up the video, which makes it mouseout, so it hides the div, then the hover event triggers again, and it shows the div, and it just loops over and over very rapidly.
You essentially will want to do one of the following:
Put the mouseover and mouseout events on both the video and the showsOnHover elements, perhaps do it on a containing parent div element. This way the mouseout event won't be triggered when it's shown; instead it will only trigger when you leave the larger containing element.
Add pointer-events: none; to your .showsOnHover class in the CSS. This makes that div transparent to mouse events. However, this could cause issues if you wanted to run any click events off that button.
Change mouseover to mouseenter as mentioned in Ram's answer
create a parent div and fire the same event on that,
<div class="parentDiv" (mouseenter)="mouseover()" (mouseleave)="mouseout()">
<video></video>
<div [hidden]="!hovering" class="showsOnHover"></div>
</div>
Use mouseenter instead of mouseover
mouseenter(e){
this.hovering = true;
this.video.play();
}
[.mouseover()] can cause many headaches due to event bubbling. For
instance, when the mouse pointer moves over the Inner element in this
example, a mouseover event will be sent to that, then trickle up to
Outer. This can trigger our bound mouseover handler at inopportune
times. See the discussion for .mouseenter() for a useful alternative.
Please see What is the difference between the mouseover and mouseenter events?
Use (mouseenter) and (mouseleave) instead of (mouseover) and (mouseout)

jQuery Click Event Triggering On Multiple Elements (I only want 1)

When my overlay comes up, everything works well, but I added some code to close out the overlay, but this code gets triggered even when I'm just clicking my arrows. The following is the code that's being triggered, which is fine when I'm not clicking the arrows to change the image. But when I click the arrows, the background which is the overlay is also being trigger, so the image is changing but the overlay is also hiding.
$('#overlay').click(function() {
$(this).fadeOut('slow');
});
How can I be able to use the arrows without it also clicking on the background overlay? If you open up the project, you will see what I'm saying.
To open the project:
https://htmlpreview.github.io/?https://github.com/rodriguesandrewb/photo_gallery_v1/blob/master/index.html
To open the repository:
https://github.com/rodriguesandrewb/photo_gallery_v1
You want to use event.stopPropagation(): https://api.jquery.com/event.stoppropagation/
This prevents the event from bubbling (being triggered by other elements)
Your outter most element is #overlay. It means that no matter where you click you'll be always clicking on your #overlay element. That is way your callback is being always triggered and closing your image.
To fix your problem and make your image close only when clicking on it you could use:
$('#changeImage').click(function() {
$(this).closest('#overlay').fadeOut('slow');
});
Ok, there's a ton of code to sort out, so I'm guessing your overlay is
<div id="overlay" style="display: block;"></div>
and your event.target is deep down inside this:
<div class="mainCenter">
<div class="container">
<div id="topFixed">
<input type="text" id="search" placeholder="Search">
</div>
<ul id="gallery">
.......
I'm not 100% sure where your event.target is, (the element you want to click and not everything else). But it's safe to assume that after you click your intended button, the event continues to bubble up the event chain. The event chain is basically your event.target's ancestors which includes#overlay` which is at the very top of the event chain.
To prevent event bubbling (btw bubbling is the default behavior but in instances such as your's it's not desired.) try placing stopPropagation() after or inside at the end of your event handler.
I wish I could be more specific as to where and how to apply this code as it pertains to your source, but you didn't provide the specific areas that concern your eventListeners, eventHandlers, etc...
The #overlay is used in this example but I suggest you use the event.target parent instead. The purpose of this code is to accept an event like 'click' on an element (i.e. button) or multiple elements (i.e. buttons) through their mutually shared parent. That's one place to click for potentially several different buttons. At first you'd think that's non-sense and you'd say, "Sure that button is clicked because the parent was clicked, but now everything the parent is chained to will trigger everything else."
That would be correct except we have stopPropagation(); at the very end of your eventHandler. That will stop propagation of the event bubbling back up the event chain, so there's no more rogue triggers lighting up everywhere. Rogue Triggers® sounds like a great band name. :P
For details and a much better explanation: http://www.kirupa.com/html5/handling_events_for_many_elements.htm
var overlay = document.querySelector("#overlay");
theParent.addEventListener("click", doSomething, false);
function doSomething(e) {
if (e.target !== e.currentTarget) {
var clickedItem = e.target.id;
alert("Hello " + clickedItem);
}
e.stopPropagation();
}

How do we make use of `mouseover` and `mouseout` event?

As JQuery document says, I have converted many lines mouseover to mouseenter because it does not fire more than once.
http://api.jquery.com/mouseover/
mouseover fires when the pointer moves into the child element as well
mouseenter fires only when the pointer moves into the bound element.
Even hover event works as mouseenter and mouseleave, not as mouseover and mouseout.
It makes me wonder why there is mouseover event if mouseenter can do it all.
For me, mouseover gets fired unpredictably when you move mouse around on an element. It seems really dependent on the depth of child elements.
Is there a good use-case of mouseover and mouseout, which needs to fire multiple times?
That I know of, there is no use case for mouseover/mouseout at all. The only reason they exist is because these events are triggered by browsers because they are in the standard DOM event list. mouseenter and mouseleave are not standard events, but they are jQuery-specific constructs.
I suppose a use case would be if you wanted the event to trigger when moving the mouse over and out of the children of the element that the events are bound to. I can't think of anything specific, but at least this functionality is available. If only mouseenter/mouseleave existed, you wouldn't have a choice in the matter.
From http://code.jquery.com/jquery-1.9.1.js:
jQuery.each({
mouseenter: "mouseover",
mouseleave: "mouseout"
}, function( orig, fix ) {
/* content snipped */
Speculation: the reason why the creators of jQuery created the mouseenter and mouseleave non-standard events is because their behavior works as you would expect the mouseover/mouseout events to work (i.e. without regard for descendants).
Because the event contains coordinates of cursor.
So if you need to track mouse coordinates under the target, you have to use 'mouseover'

Javascript Mouseover bubbling from children

Ive got the following html setup:
<div id="div1">
<div id="content1">blaat</div>
<div id="content1">blaat2</div>
</div>
it is styled so you can NOT hover div1 without hovering one of the other 2 divs.
Now i've got a mouseout on div1.
The problem is that my div1.mouseout gets triggered when i move from content1 to content2, because their mouseouts are bubbling.
and the event's target, currentTarget or relatedTarget properties are never div1, since it is never hovered directly...
I've been searching mad for this, but I can only find articles and solutions for problems who are the reverse of what I need. It seems trivial but I can't get it to work...
The mouseout of div1 should ONLY get triggered when the mouse leaves div1.
One of the possibilities would be to set some data on mouse enter and mouseleave, but I'm convinced this should work out of the box, since it is just a mouseout...
EDIT:
bar.mouseleave(function(e) {
if ($(e.currentTarget).attr('id') == bar.attr('id')) {
bar.css('top', '-'+contentOuterHeight+'px');
$('#floatable-bar #floatable-bar-tabs span').removeClass('active');
}
});
changed the mouseout to mouseleave and the code worked...
Use the mouseleave event instead or mouseout for this, it handles your specific issue. See here for details
From the docs on the difference:
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.
Example markup:
<div id="outer">
Outer
<div id="inner">
Inner
</div>
</div>
The hover method has two parameters, first for mouse in and second for mouse out.
$('your_div').hover(function(){
// your code here.
}, function(){// any mouse out code here})

Categories

Resources