I have a parent element with several child elements, some of which have their own event listeners and others don't. The parent element has click handler that I want to run only if I click on the parent itself and not any of the child elements.
document.getElementById('parent').addEventListener('click', ()=> console.log('parent clicked'))
document.getElementById('child2').addEventListener('click', ()=> console.log('child2 clicked'))
#parent {
height: 300px;
width: 300px;
background-color: Lightgreen;
wrap: true;
display: flex;
flex-direction:column;
gap: 20px;
padding: 50px 50px;
}
#parent * {
height: 100px;
width: 100px;
background-color: white;
text-align: center;
display: grid;
place-items: center;
}
<div id="parent"> parent -Only log 'parent' when green background is clicked and nothing else-
<div id="child1">child1 <br> -Nothing should happen when clicked-</div>
<div id="child2">child2 <br> -Should only log -child 2 if clicked-</div>
</div>
I tried stopPropagation()
, it works to stop the event bubbling, but I'd need to add it to all child event handlers, and I still can't stop the parent from firing when clicking on objects without event listeners.
Is there a way to restrict the parent handler only when clicking on the element itself?
CodePudding user response:
event.currentTarget
might be helpful to verify that the event is coming from that specific element on which you set the event, not from a child. A quick definition of it from MDN's documentation:
The
currentTarget
read-only property of theEvent
interface identifies the current target for the event, as the event traverses the DOM. It always refers to the element to which the event handler has been attached, as opposed toEvent.target
, which identifies the element on which the event occurred and which may be its descendant.
And the advantage of doing so on @CertainPerformance's solution (which is great) is that you don't have to know that element.
document.getElementById('parent').addEventListener('click', (e)=> {
if(e.currentTarget===e.target){
console.log('parent clicked');
}
});
document.getElementById('child2').addEventListener('click', (e)=> {
if(e.currentTarget===e.target){
console.log('child2 clicked');
}
});
#parent {
height: 300px;
width: 300px;
background-color: Lightgreen;
wrap: true;
display: flex;
flex-direction:column;
gap: 20px;
padding: 50px 50px;
}
#parent * {
height: 100px;
width: 100px;
background-color: white;
text-align: center;
display: grid;
place-items: center;
}
<div id="parent"> parent -Only log 'parent' when green background is clicked and nothing else-
<div id="child1">child1 <br> -Nothing should happen when clicked-</div>
<div id="child2">child2 <br> -Should only log -child 2 if clicked-</div>
</div>
CodePudding user response:
This is just a small addition to this answer, and not meant as an answer. Event with e.currentTarget === e.target
a click on a child could trigger parent clicked
if pointer-events: none
is utilized on the child.
But if pointer-events: none
is used then you can't do anything about it anyway, as explicitly say that this element should be ignored for event handling.
document.getElementById('parent').addEventListener('click', (e) => {
if (e.currentTarget === e.target) {
console.log('parent clicked');
}
});
#parent {
height: 300px;
width: 300px;
background-color: Lightgreen;
wrap: true;
display: flex;
flex-direction: column;
gap: 20px;
padding: 50px 50px;
}
#parent * {
height: 100px;
width: 100px;
background-color: white;
text-align: center;
display: grid;
place-items: center;
}
[data-no-pointer-event] {
pointer-events: none;
}
<div id="parent"> parent -Only log 'parent' when green background is clicked and nothing else-
<div id="child1">child1 <br> - Nothing should happen when clicked -</div>
<div id="child2" data-no-pointer-event>child 2 - will log parent clicked - </div>
</div>
CodePudding user response:
Check if the .target
is the parent - if it is, that means the click was directly on the parent, and isn't an event bubbling up from a child.
const parent = document.getElementById('parent');
parent.addEventListener('click', (e) => {
if (e.target === parent) {
console.log('parent clicked');
}
});
document.getElementById('child2').addEventListener('click', () => console.log('child2 clicked'))
#parent {
height: 300px;
width: 300px;
background-color: Lightgreen;
wrap: true;
display: flex;
flex-direction: column;
gap: 20px;
padding: 50px 50px;
}
#parent * {
height: 100px;
width: 100px;
background-color: white;
text-align: center;
display: grid;
place-items: center;
}
<div id="parent"> parent -Only log 'parent' when green background is clicked and nothing else-
<div id="child1">child1 <br> -Nothing should happen when clicked-</div>
<div id="child2">child2 <br> -Should only log -child 2 if clicked-</div>
</div>