4

Consider the following code as an example:

<div id="parent">
  <div id="child">info goes here</div>
</div>

//javascript
function something{
//do something;}
//initial attempt
document.getElementById('parent').addEventListener('click',something);
//event capture
document.getElementById('parent').addEventListener('click',something,true);

When I click on the parent element I would like it to do something, and when I click the child I want it to do nothing. The problem is that when I click in the child element it is triggering 'something'. I thought that it may be event bubbling, such that if I clicked on the child element, the event would bubble up from there to the parent. So then I was thinking about an event capture, but that also causes this problem.

Any advice or suggestions on how to accomplish this would be greatly appreciated.

nCoder
  • 106
  • 9
Paul Carlson
  • 379
  • 5
  • 18
  • 1
    Possible duplicate of [How do I prevent a parent's onclick event from firing when a child anchor is clicked?](https://stackoverflow.com/questions/1369035/how-do-i-prevent-a-parents-onclick-event-from-firing-when-a-child-anchor-is-cli) – Michelangelo May 07 '19 at 23:29

3 Answers3

7

Instead, check if the element originating the event Event.target - was indeed the desired element.
PS: Don't confuse with Event.currentTarget which (in contrast) is always the Element who has the Event handler attached.

function something (evt){
  if (evt.target !== this) return; // Do nothing
  // else...
  console.log(`#${this.id} clicked`);
}

const el_parent = document.getElementById('parent');
el_parent.addEventListener('click', something);

// Example why you should not use `Event.stopPropagation()`...
document.body.addEventListener('click', () => console.log("BODY is notified!"));
<div id="parent">
  PARENT ELEMENT
  <div id="child">CHILD ELEMENT</div>
</div>

Don't use Event.stopPropagation()

Event.stopPropagation() would be an idea, but a bad one, since we should avoid an application to (at some layer) prevent an event to bubble - and eventually notify other elements that such an event happened. Imagine your body listens for click events to close custom select dropdowns... If you have elements wandering around your app, and that use Event.stopPropagation() - clicking on such element an opened dropdown will not close - resulting in broken UI. And this was just a simple example.

Roko C. Buljan
  • 196,159
  • 39
  • 305
  • 313
  • 1
    Nice alternative to the standard answer, and illustrates why using `stopPropagation` might be a bad idea (ie: other elements like `body` might need to know about the click). It's also a good approach for a case where a parent might want to ignore clicks on several children, without having to add `stopPropagation` to each one individually. – ericgio Nov 16 '19 at 21:49
  • Exactly. Thank you for the support @ericgio – Roko C. Buljan Nov 17 '19 at 02:21
  • is it safer to use `event.currentTarget` rather than `this` to prevent unexpected behaviour in arrow function, so `event.currentTarget` === `event.target` – nnfans Mar 24 '23 at 03:30
4

Use event.stopPropagation to stop event bubbling:

function something() {
  console.log("something");
}
document.getElementById('parent').addEventListener('click', something);
document.getElementById('child').addEventListener('click', e => e.stopPropagation());
<div id="parent">
  Parent info goes here!
  <div id="child">Child info goes here!</div>
</div>
Jack Bashford
  • 43,180
  • 11
  • 50
  • 79
  • Thank you for the answer, it solved my problem. So if I understand correctly, even though I clicked on the child it was still the 'click' event that bubbled up and then triggered the parents listener? – Paul Carlson May 07 '19 at 23:21
  • Yes, that's correct - and that's what `stopPropagation` stops happening. – Jack Bashford May 07 '19 at 23:31
  • @PaulCarlson you should better not use `Event.stopPropagation()` and specially not assigning an event listener to every single element that you want to prevent the event from bubbling. It's incorrect. – Roko C. Buljan May 07 '19 at 23:35
0

It is event bubbling. Just because you are handling the click event on the child, does not mean it stops bubbling to the parent.

There are two approaches to this. The first one is to stop the event from propagating like this: document.getElementById('child').addEventListener('click',(e) => { e.stopPropagation(); something() },true);

The second is to check the event target and only run something when the deepest element that caused the click event is the child element:

document.getElementById('child').addEventListener('click',(e) => { e.target.id == "child" ? something() : nothing() },true);

dimlucas
  • 5,040
  • 7
  • 37
  • 54