13

How do I implement event delegation for the mouseenter event?

I'm looking for the equivalent to this jQuery code, but didn't manage to understand how jQuery does it internally:

$(document).on('mouseenter', '.demo', foo);

I've seen this other question about it, but no proper solution was provided.

I've also read Mozilla docs regarding mouseenter and delegation, and besides saying it's not compatible with any browser, the example they provided throws error on the JS console and doesn't work.

I've also checked this codepen, which doesn't work on Chrome either (didn't try other browsers).

Any idea?

This is what I'm trying so far, but the target element seems to always bubble up:

document.addEventListener('mouseenter', function(e) {
    console.log('==============================');
    console.log(e.currentTarget); //document
    console.log(e.target); //document 
    console.log(e.relatedTarget); //nothing
    console.log(e.handleObj); //nothing
});

You can play with it in this jsfiddle.

Alvaro
  • 40,778
  • 30
  • 164
  • 336
  • 2
    They might not exist on load. They can be dynamically added and I have no control over when and how. – Alvaro May 04 '18 at 14:37
  • Oh, right, I forgot that was a thing – Luca Kiebel May 04 '18 at 14:38
  • We opted for going for mouseover and a variable to store the last element hovered over. That way event.target will actually contain the element hovered over and you can check its class to see if it should do something. Next hover, you can check if the next element hovered over is a child or not of the previous one. – Shilly May 04 '18 at 14:42
  • @Shilly but how do you get the target element? I'm always getting `document` when trying to use delegation. `e.target` doesn't give me the actual element. – Alvaro May 04 '18 at 14:49
  • @LucaRainone can't seem to easily extract what I need from jquasi – Alvaro May 04 '18 at 15:01

2 Answers2

22

You have to add the event listener on capturing phase, passing true as third argument:

document.body.addEventListener("mouseenter", function(e) {
    if(e.target.className === "demo") {
        console.log("catched");
    }
},true); // capturing phase

You can do something of more elaborated in order to catch the selector. But that's the key.

Demo here https://codepen.io/anon/pen/Xqaxwd

charlietfl
  • 170,828
  • 13
  • 121
  • 150
Luca Rainone
  • 16,138
  • 2
  • 38
  • 52
-2

Maybe you can use mousemove and keep track of the current element (keeping in mind parents) like this:

let lastTarget = null;

document.addEventListener('mousemove', function(e) {
 const target = checkWithParents(e.target);
 if (target && target != lastTarget) {
   alert('mouseenter');
 }
 lastTarget = target;
})

function checkWithParents(el) {
  while (el) {
    if (el && el.classList && el.classList.contains('demo')) {
      return el;
    }
    el = el.parentNode;
  }
  return null;
}
.demo {
  background-color: tomato;
  height: 300px;
  width: 300px;
  margin: 50px;
}
<div class="demo"><div class="inner"></div></div>
<div class="demo"><div class="inner"></div></div>
Amr Noman
  • 2,597
  • 13
  • 24
  • Nop. Need mouse enter. The mouse might not move :) – Alvaro May 04 '18 at 14:56
  • @Alvaro I think even jquery doesn't work like how you want, check this [fiddle](https://jsfiddle.net/amrnn/d8d6kj91/), put your mouse to the right of the div and when the div moves over your mouse nothing will happen (unless you move the mouse). – Amr Noman May 04 '18 at 15:03
  • I can scroll up and down without moving the mouse (only using wheel effect of the trackpad) and the alert keeps firing. – Alvaro May 04 '18 at 15:14