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)
Related
Consider this code.
I cannot figure out why it behaves as it does. All I need is the play icon alternating with pause icon everytime I click anywhere inside the <td>. It behaves as expected when I click inside the <td> but outside the icon itself. However, if I click on the icon itself, it behaves fine the first time, and then stops.
'The ionicon is wrapped in the <a> tag, which is a child of the <td> element. The event listener is on the <td>, so what could be the problem?
Thanks.
As #Vijai said your problem with the hover event .. And While I don't know a lot about your project and you really need .empty() on hover or you just need to hide() the icon .. You can try this part of code instead of yours
var hovOn = function(event) {
if($(this).find('a').length < 1){
$(this).html(playButtonTemplate);
}else{
$(this).find('a').show();
}
};
var hovOff = function(event) {
$(this).find('a').hide();
}
Codepen Here
Ok, figured it out. It seems like an artefact that arises from creating an element from a template and the way mouseenter is implemented.
The problem is that the mouseenter event (hoverOn part of the .hover()) triggers when it shouldn't. Each time a new ionicon is created from a template it will trigger the mouseenter event if the cursor moves a little.
Logically mouseenter shouldn't be triggered when the element appears, because mouseenter should trigger when a listener element or its descendent is hovered over, and then only call when the cursor leaves all of the elements associated with the event and then enters again. I think this is an artefact of creating an element from a template like that. Maybe it's because DOM get updated and it discards the fact that the cursor is already within the element. So mouseenter triggers again and in turn triggers creating a new play icon. Then it repeats..
This codepen should explain it well. If you hover over the play button the mouseenter counter will increment each time you move your mouse even a little, because each time a mouse is moved, a new play button is created. If you delete the line that creates a new play button, it behaves as mouseenter should, triggering only when the cursor enters the element.
When you click on the <a> tag it seems it is also triggering the parent <td> hover event. Once solution is try the below code for hover.
var hovOn = function(event) {
if(playOrPause==='play') {
$(this).html(pauseButtonTemplate);
playOrPause = 'pause';
} else {
$(this).html(playButtonTemplate);
playOrPause = 'play';
}
};
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();
}
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'
I'm familiar with jQuery but i have one little setback. I would like the function to be called only when i just hover the element, and not when im already hovering it and i slightly move the mouse.
I simply want the function to be called only if i'm entering the area of the element from outside of it.
I hope this makes sense.
Any ideas?
The hover method binds an event handler for mouseenter and one for mouseleave, so it won't trigger any event whenever the mouse is moved within the element.
It's the mousemove event that is used for that. Perhaps you are binding that also somewhere?
If you only want to handle the event when the mouse enters, and not when it leaves, used the mouseenter method instead of hover.
maybe you need mouseenter and not the whole hover event
$(div).mouseenter()
Yes hover will bind a mouseenter and a mouseleave to your selector:
try:
$(div).mouseenter(function(){
//Do whatever you want to do on your mouse enter.
)}
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})