Reputation: 1734
I'm trying to create web-page, and to improve performance, I decide to use event delegation, instead of direct binding, but I came across with strange behavior of event delegation or I missed something...
Here is structure of my HTML
<div>
<section class="myClass" data-link="section 1">
<h1>Heading 1</h1>
<p>Some text....</p>
</section>
</div>
I want to entire section was clickable, but while clicking h1
or p
element in section
event.target
on that moment is h1
or p
and not section
, so expression in if statement fails...
function delegate(ele) {
ele.parentNode.addEventListener("click", function (e) {
if (e.target.nodeName.toLowerCase() === "section" && e.target.classList.contains("myClass")) {
console.log("delegate " + e.target.getAttribute("data-link"));
}
}, false);
}
I already have solution with direct binding, but it would be good is achieved in the same result with event delegation. Here is jsFiddle
function direct(ele) {
[].forEach.call(ele, function (value, index, array) {
value.addEventListener("click", function(e) {
console.log("direct " + value.getAttribute("data-link"));
}, false);
});
}
Thanks in advance!
Upvotes: 2
Views: 627
Reputation: 1734
I found the solution with CSS pointer-events
.myClass * {
pointer-events: none;
}
or with JavaScript
(function () {
"use strict";
var ele = document.querySelector(".myClass").parentNode;
delegate(ele);
function delegate(ele) {
ele.addEventListener("click", function (e) {
var target = e.target;
while (!(target.nodeName.toLowerCase() === "section" && target.classList.contains("myClass"))) {
target = target.parentNode;
if (target === ele) {
break;
}
}
if (target.nodeName.toLowerCase() === "section" && target.classList.contains("myClass")) {
console.log("delegate " + target.getAttribute("data-link"));
}
});
}
}());
Upvotes: 2
Reputation: 287980
Add the event listener to ele
instead of ele.parentNode
, and use this
instead of e.target
.
function delegate(ele) {
ele.addEventListener("click", function (e) {
if (this.nodeName.toLowerCase() === "section" && this.classList.contains("myClass")) {
console.log("delegate " + this.getAttribute("data-link"));
}
}, false);
}
Be aware that e.target
is the element the event was dispatched on. But in your case you don't want that, you want the element which has the event handler, so use this
(or ele
).
Upvotes: 1
Reputation: 19294
Once you handled the click, you can walk the visual tree, starting from the target, to find the information you need.
You might seek by type (node name), by tag, ... for the sake of the example, i just seek on element up to get a 'data-link' attribute if i don't find one on the target, but you have many choices here.
Edit : another idea is to use event.currentTarget, to get the element on which you hooked the event.
The updated fiddle will print :
delegate call on h1 or p of section 1
when you click on h1 or p1
and it will print :
delegate section 1
when you click on the whole section.
function delegate(ele) {
ele.parentNode.addEventListener("click", delegateHandler, false);
}
function delegateHandler (e) {
var target = e.target;
var attribute = target.getAttribute("data-link");
// if target has no attribute
// seek it on its parent
if (!attribute) {
attribute = target.parentNode.getAttribute("data-link");
}
if ( target.classList.contains("myClass") ) {
console.log("delegate " + attribute);
}
else console.log('delegate call on h1 or p of ' + attribute);
}
Rq : i didn't get why you hook the event on the parent of the element, might be simpler not to do it. :-)
Upvotes: 3