Reputation: 1055
I am trying to capture the id on each card from the root element. However, every time I click on a nested element I get empty string. However, I want the id from the wrapping card while listening on the root element cards. I want to handle both bubbling and capturing cases as this is part of a larger structure. I only want answers in vanilla js, and Javascript, no css please.
cards.addEventListener('click', evt => {
if (evt.target !== evt.currentTarget) {
var clickedItem = evt.target.id
console.log(clickedItem);
}
});
.card {
/* Add shadows to create the "card" effect */
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
}
/* On mouse-over, add a deeper shadow */
.card:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}
/* Add some padding inside the card container */
.container {
padding: 2px 16px;
}
<div id="cards" style="margin: auto; width: 50%;">
<div class="card" id="1234567"><img src="img_avatar.png">
<div class="container">
<h4>1st Note</h4>
<p>Note Body</p>
</div>
</div>
<div class="card" id="1234547"><img src="img_avatar.png">
<div class="container">
<h4>2nd Note</h4>
<p>Note Body2</p>
</div>
</div>
<div class="card" id="721680"><img src="img_avatar.png">
<div class="container">
<h4>3Note Body</h4>
<p>Note Body3</p>
</div>
</div>
</div>
Upvotes: 1
Views: 2348
Reputation: 18005
Yes, one listener is a good requirement. As it happens you only need to change the line where you get your target:
cards.addEventListener('click', evt => {
console.log( evt.target.closest( '.card' ).id );
});
Complete example:
cards.addEventListener('click', evt => {
alert( evt.target.closest( '.card' ).id );
});
.card {
/* Add shadows to create the "card" effect */
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
}
/* On mouse-over, add a deeper shadow */
.card:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}
/* Add some padding inside the card container */
.container {
padding: 2px 16px;
}
<div id="cards" style="margin: auto; width: 50%;">
<div class="card" id="1234567"><img src="img_avatar.png">
<div class="container">
<h4>1st Note</h4>
<p>Note Body</p>
</div>
</div>
<div class="card" id="1234547"><img src="img_avatar.png">
<div class="container">
<h4>2nd Note</h4>
<p>Note Body2</p>
</div>
</div>
<div class="card" id="721680"><img src="img_avatar.png">
<div class="container">
<h4>3Note Body</h4>
<p>Note Body3</p>
</div>
</div>
</div>
Upvotes: 3
Reputation: 65825
The issue is that depending on where you click, you may wind up clicking on <div class="container">
, which has no id
.
Let's examine your HTML structure:
<!-- You have your click handler attached to this parent element. It's true
that any clicks on descendant elements will bubble up to this parent,
but when you handle it here, this parent becomes event.currentTarget
and while this element does have an id, it's not the id you want. -->
<div id="cards" style="margin: auto; width: 50%;">
<!-- This is the element level that has the id that you want, so
this is the element level that should have the event handlers. -->
<div class="card" id="1234567">
<!-- If the user clicks in the area of the following elements (which
they are most likely to because it takes up most of the space
on the card) one of these elements will become `event.target`
and none of these elements has an id to get. That's why you are
getting an empty string in your console. -->
<img src="img_avatar.png">
<div class="container">
<h4>1st Note</h4>
<p>Note Body</p>
</div>
</div>
... inner pattern repeats ...
</div>
You need to assign the click event to each .card
, not the parent .cards
and then you can get the currentTarget.id
Array.prototype.slice.call(document.querySelectorAll(".card")).forEach(function(c){
c.addEventListener('click', evt => {
console.log(evt.currentTarget.id);
});
});
.card {
/* Add shadows to create the "card" effect */
box-shadow: 0 4px 8px 0 rgba(0, 0, 0, 0.2);
transition: 0.3s;
}
/* On mouse-over, add a deeper shadow */
.card:hover {
box-shadow: 0 8px 16px 0 rgba(0, 0, 0, 0.2);
}
/* Add some padding inside the card container */
.container {
padding: 2px 16px;
}
<div id="cards" style="margin: auto; width: 50%;">
<div class="card" id="1234567"><img src="img_avatar.png">
<div class="container">
<h4>1st Note</h4>
<p>Note Body</p>
</div>
</div>
<div class="card" id="1234547"><img src="img_avatar.png">
<div class="container">
<h4>2nd Note</h4>
<p>Note Body2</p>
</div>
</div>
<div class="card" id="721680"><img src="img_avatar.png">
<div class="container">
<h4>3Note Body</h4>
<p>Note Body3</p>
</div>
</div>
</div>
Upvotes: 0