chuckd
chuckd

Reputation: 14530

Mouseover and mouseout trigger multiple times

I have these two on mouseover and mouseout events in JS. They are for checking wether I'm hovering over a panel on my page. But the problem is when I hover over a panel it triggers (good), but then when I hover over another element inside that panel it triggers a the mouseout event and then the mouseover events again when I move to another part inside the panel.

I only want the mouseover and mouseout events firing once! Once for entering the panel another for leaving it. Is there a way to propagate the on mouseover call to all child elements in the div.panel. It seems like that would correct it.

Here are my events

$(document).off("mouseover").on("mouseover", "div.panel", function() {
   var panelSpaceId = $(this).attr("data-spaceId");
   var marker = _.find(scope.markers, function(item) {
     return item.spaceId == panelSpaceId
   })
   google.maps.event.trigger(marker, "mouseover");
   console.log("over" + marker.spaceId);
 });

 $(document).off("mouseout").on("mouseout", "div.panel", function() {
   var panelSpaceId = $(this).attr("data-spaceId");
   var marker = _.find(scope.markers, function(item) {
     return item.spaceId == panelSpaceId
   })
   google.maps.event.trigger(marker, "mouseout");
   console.log("out" + marker.spaceId);
 });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Upvotes: 29

Views: 23702

Answers (1)

Terry
Terry

Reputation: 66103

You can avoid this issue by using mouseenter instead of mouseover, and mouseleave instead of mouseout. The reason is simple: mouseenter is only fired when the cursor "enters" the element, which includes its children—so hovering over the child of the element does not re-fire the mouseenter event.

This similar logic applies to mouseleave vs of mouseout. You can see this effect happening based on a fiddle created by @gilly3 in his answer to a similar question. I am not marking your question as duplicate because your answer is primarily troubleshooting mouseover/leave events instead of asking about the distinct between mouseover/enter and mouseout/leave.

It is helpful to imagine this:

  • entering means when your cursor enters the bounds of the element. Even when you are in a child node, you are still within the bounds, hence it is never triggered multiple times.
  • (h)overing can be visualised as seeing your element on a canvas. If the element you your cursor over is visible on the screen, the mouseover event is triggered. The cursor is no longer over the parent element when your cursor moves over the child element, hence when you go back and forth the event is triggered over and over again.

Here is your modified code, where I simply replaced the offending events with the right ones:

$(document).off("mouseenter").on("mouseenter", "div.panel", function() {
  var panelSpaceId = $(this).attr("data-spaceId");
  var marker = _.find(scope.markers, function(item) {
    return item.spaceId == panelSpaceId
  })
  google.maps.event.trigger(marker, "mouseenter");
  console.log("over" + marker.spaceId);
});

$(document).off("mouseleave").on("mouseleave", "div.panel", function() {
  var panelSpaceId = $(this).attr("data-spaceId");
  var marker = _.find(scope.markers, function(item) {
    return item.spaceId == panelSpaceId
  })
  google.maps.event.trigger(marker, "mouseleave");
  console.log("out" + marker.spaceId);
});

Upvotes: 72

Related Questions