I have a forEach
loop that gets the attribute of any element that has the specified attribute on my page. It looks something like this:
const cursorActionElements = document.querySelectorAll("[data-cursor]");
cursorActionElements.forEach((el) => {
const elAttr = el.getAttribute("data-cursor");
el.addEventListener('mouseover', () => {
console.log(elAttr)
});
});
It all works fine. It goes through and gets all elements that have the data-cursor
attribute and stores its value in the elAttr
variable. However, for some reason, If the parent of the target happens to ALSO have a data-cursor
attribute, it returns both the target's data-cursor
value, AND its parent's data-cursor
value.
I'm really not sure how to solve this issue. I've thought of retrieving the data-cursor
value on mouseover
but, that just means I need to use yet another event listner and it seems to slow my site down a bit.
Please help.
The issue is because the event is propagating up the DOM from the child to the parent, so the event handler fires once per element. To fix this you can call stopPropagation()
on the event passed to the event handler.
Also note that it would be a better idea to read the data
attribute from the Event object as well, to avoid any scope/closure issues which may arise when relying on the variable set in a loop within an event handler.
Here's a working example with the above changes made:
const cursorActionElements = document.querySelectorAll("[data-cursor]");
cursorActionElements.forEach((el) => {
el.addEventListener('mouseover', e => {
e.stopPropagation();
const elAttr = e.currentTarget.getAttribute("data-cursor");
console.log(elAttr)
});
});
<div data-cursor="foo">foo</div>
<div data-cursor="bar">
bar
<div data-cursor="foobar">
foobar
</div>
<div>
no data attribute
</div>
</div>