ConorReidd ConorReidd - 2 months ago 18
jQuery Question

jQuery - Stop child hover triggering parent click with relative elements

This is not a duplicate question. I've looked around stackoverflow and none of the following questions have worked for me.

jQuery stop child elements animate on hover of parent

How to have click event ONLY fire on parent DIV, not children?

I have a parent element

.cover
and a single child element inside called
.details-wrapper


When i hover over the child element of the parent, the parent hover is being triggered. This is how i want it to be (Sorry about editing);

enter image description here

Currently what i have tried (And failed) is using
return false;
and
stopPropagation


The image has
position: relative
and
top: 160px
so it comes out of the original
.cover
wrapper

It's really weird because the way i hover ovre the element determines how the jquery works. Here's a gif showing that.

https://gyazo.com/7153f3b8d3a57d0cfbb6b8d7d56caf0a

The jQuery i'm using is:

$(".cover").not('.details-wrapper').hover(function(e) {
if (e.target === this) {
$(".cover").css("background","url(url1), url('"+cover._url+"')");
}
}, function() {
$(".cover").css("background","url('"+cover._url+"')");
});


I'm unsure how I can fix this so when i hover over the child element it stops the hover for the parent from triggering.

Just for further clarity, this doesnt work either:

$(".cover").hover(function(e) {
if (e.target === this) {
$(".cover").css("background","url(url1), url('"+cover._url+"')");
}
}, function() {
$(".cover").css("background","url('"+cover._url+"')");
});

$(".cover .details-wrapper").hover(function(e) {
e.stopPropagation();
});

Answer

Don't rely on the .hover() function, which is a shorthand for the .mouseenter() and .mouseleave() events. You need the .mouseover() and .mouseout() events, and it will trigger appropriately when entering/leaving child nodes:

$(function() {
  $('.cover').on('mouseover', function(e) {
      if (e.target === this) {
        $('.cover').css('background','url(url1), url(''+cover._url+'')');
      }
    })
    .on('mouseout', function() {
       $('.cover').css('background','url(''+cover._url+'')');
    });
});

The simple explanation is this: when you are using .hover() (hence the mouseenter and mouseleave were being listened), they are not triggered when you enter or leave the child elements. This causes the event to appear to be "propagated" because in the background, the mouseleave event was never called when you enter the child. However, the mouseout event will be called, resulting in the desired behaviour.

Here is a proof-of-concept example (using a red background to indicate mouseover events):

$(function() {
  $('.cover').on('mouseover', function(e) {
      if (e.target === this) {
        $('.cover').css('background', 'red');
      }
    })
    .on('mouseout', function() {
      $('.cover').css('background', 'transparent');
    });
});
* {
  padding: 0;
  margin: 0;
}
.cover {
  padding: 2rem;
  text-align: center;
  position: relative;
  height: 10rem;
}
.cover .details-wrapper {
  background-color: #eee;
  position: absolute;
  top: 50%;
  left: 50%;
  padding: 2rem;
  transform: translate(-50%,-50%);
  }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="cover">
  Cover
  <div class="details-wrapper">
    Details wrapper
  </div>
</div>

There is a thread on SO that discusses the difference between these events: Jquery mouseenter() vs mouseover()