I currently have an issue where I want to be able to check when a event is click. I want to use event delegation for this and so I have setup an event listener on a parent div, which listens for clicks:
document.querySelector('.side-nav').addEventListener('click', e => {
console.log(e.target.data.set.param);
});
This is my DOM:
<div class="side-nav">
<div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
<p class="side-nav-button-icon"><i class="fas fa-home"></i></p>
</div>
<div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
<p class="side-nav-button-icon"><i class="fas fa-cross"></i></p>
</div>
</div>
I want to be able to get the data-page
attribute when the right div is clicked, ie when the div dashboard-shortcut
is clicked. Is there any way that I can do this?
Thank you very much in advance.
I currently have an issue where I want to be able to check when a event is click. I want to use event delegation for this and so I have setup an event listener on a parent div, which listens for clicks:
document.querySelector('.side-nav').addEventListener('click', e => {
console.log(e.target.data.set.param);
});
This is my DOM:
<div class="side-nav">
<div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
<p class="side-nav-button-icon"><i class="fas fa-home"></i></p>
</div>
<div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
<p class="side-nav-button-icon"><i class="fas fa-cross"></i></p>
</div>
</div>
I want to be able to get the data-page
attribute when the right div is clicked, ie when the div dashboard-shortcut
is clicked. Is there any way that I can do this?
Thank you very much in advance.
Share Improve this question edited Sep 29, 2019 at 19:34 Asons 87.4k12 gold badges118 silver badges174 bronze badges asked Sep 29, 2019 at 17:37 dan123123dan123123 972 silver badges11 bronze badges3 Answers
Reset to default 4Unless you expect to have elements added dynamically, don't use event delegation, simply attach a listener on each target, in this case the .side-nav > [data-page]
elements.
With that you avoid all detection issues, like which actual div
where clicked etc., where this
will be the targeted element, e.g. this.dataset.page
.
...and a bonus; less code, less error prone, easier maintenance.
Note, you used data.set.param
, should be dataset.param
, where param
here is page
(data-page
)
Stack snippet
document.querySelectorAll('.side-nav > [data-page]').forEach(el => {
el.addEventListener('click', function() {
console.log(this.dataset.page);
});
});
<div class="side-nav">
<div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
<p class="side-nav-button-icon"><i class="fas fa-home">Home</i></p>
</div>
<div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
<p class="side-nav-button-icon"><i class="fas fa-cross">Page2</i></p>
</div>
</div>
Based on a ment, where OP said they do load elements dynamically, added a 2nd sample.
Using if (e.target !== this && this.contains(e.target))
we can check so it is not the .side.nav
itself (e.target !== this
) someone clicked on, but one of its children (this.contains(e.target)
), before continue.
And if, with e.target.closest('[data-page]').dataset.page
we get the targeted element.
Note, as mentioned in another ment, if you have nested .side-nav
with children having the same classes/attribute, you might need to adjust, where e.g. extending the selector for closest()
, to closest('.side-nav > [data-page]')
, should be enough, still, difficult to say with certainty.
Stack snippet
document.querySelector('.side-nav').addEventListener('click', function(e) {
if (e.target !== this && this.contains(e.target)) {
console.log(e.target.closest('[data-page]').dataset.page);
}
});
<div class="side-nav">
<div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
<p class="side-nav-button-icon"><i class="fas fa-home">Home</i></p>
</div>
<div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
<p class="side-nav-button-icon"><i class="fas fa-cross">Page2</i></p>
</div>
</div>
// use closest method for finding actual element
document.querySelector('.side-nav').addEventListener('click', e => {
var elem = e.target.closest("[data-page]");
if (elem && elem.getAttribute('data-page') !== 'root') {
console.log(elem.getAttribute("data-page"));
}
});
Note: prevent stop finding element till root
<div class="side-nav" data-page='root'>
<div class="side-nav-button side-nav-active pointer" id="dashboard-shortcut" title="Home" data-page="dashboard">
<p class="side-nav-button-icon"><i class="fas fa-home"></i></p>
</div>
<div class="side-nav-button side-nav-active pointer" id="another-div-shortcut" title="page2" data-page="page2">
<p class="side-nav-button-icon"><i class="fas fa-cross"></i></p>
</div>
</div>
The target
property of an event will be the element clicked. In your scenario the element clicked can be any HTML element you shown in your example: The p
or the i
inside the .side-nav-button
, the .side-nav-button
itself or even the .side-nav
where you attach the event.
What I can think of is to get the target element, check if has a data-page
attribute and if not, go for the parent and repeat the check. This way if, for example, the i
element is clicked, it will check itself, then will check the p
and finally its .side-nav-button
.
Hence:
document.querySelector('.side-nav').addEventListener('click', e => {
let el = e.target;
// The loop will stop when there's a page dataset
// Also will stop when the element that is checking is .side-nav (event.currentTarget), as there's no need to check beyond that.
while(el && el != event.currentTarget && !el.dataset.hasOwnProperty("page")) {
el = el.parentNode;
}
let page = el && el.dataset.page;
if (page) {
console.log(page);
}
});