Home > Enterprise >  Stop parent event handler form firing without editing all child event handlers
Stop parent event handler form firing without editing all child event handlers

Time:06-19

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 the Event 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 to Event.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>

  • Related