233

I have a div which I have attached an onclick event to. in this div there is a tag with a link. When I click the link the onclick event from the div is also triggered. How can i disable this so that if the link is clicked on the div onclick is not fired?

script:

$(document).ready(function(){
    $(".header").bind("click", function(){
         $(this).children(".children").toggle();
    });
})

html code:

<div class="header">
    <a href="link.html">some link</a>
    <ul class="children">
        <li>some list</li>
    </ul>
</div>
Merec
  • 2,691
  • 1
  • 12
  • 21
John
  • 19,837
  • 40
  • 111
  • 151

7 Answers7

441

Do this:

$(document).ready(function(){
    $(".header").click(function(){
        $(this).children(".children").toggle();
    });
   $(".header a").click(function(e) {
        e.stopPropagation();
   });
});

If you want to read more on .stopPropagation(), look here.

Nick Craver
  • 610,884
  • 134
  • 1,288
  • 1,151
122

Or, rather than having an extra event handler to prevent another handler, you can use the Event Object argument passed to your click event handler to determine whether a child was clicked. target will be the clicked element and currentTarget will be the .header div:

$(".header").click(function(e){
     //Do nothing if .header was not directly clicked
     if(e.target !== e.currentTarget) return;

     $(this).children(".children").toggle();
});
xr280xr
  • 11,741
  • 7
  • 78
  • 118
  • 9
    To me this is a more elegant solution since you don't have to add an explicit preventDefault() to every child element. – Ryan Griggs Oct 16 '16 at 19:32
  • 6
    And it works if you have independent events on child unlike the accepted answer. Definitely cleaner and better solution – BozanicJosip Dec 13 '16 at 12:54
  • 2
    In most circumstances you will not care about this, but if for whatever reason you need to support IE6-8, they [do not have `currentTarget`](https://developer.mozilla.org/en-US/docs/Web/API/Event/currentTarget). A workaround is to replace it with `this`, as suggested in [another answer](http://stackoverflow.com/a/6411507/2737565). – Alexander Jank Mar 09 '17 at 04:48
  • This is a cleaner solution than setting an extra listener to just catch clicks. – Micros May 03 '17 at 15:21
  • this code worked better for me` var target=$(e.target); if(!target.is("span")) return;` – Cr1xus May 25 '18 at 10:00
  • Brilliant! Live saver :-) – Grashopper Nov 13 '18 at 10:32
  • This worked great for me. in my case, I had a menu that had 100% page height in mobile. view on the ul. I wanted to collapse my menu if someone tapped the ul, but it was also triggering the collapse when an li was tapped. This prevented that. – Loopy Apr 05 '21 at 14:05
21

Better way by using on() with chaining like,

$(document).ready(function(){
    $(".header").on('click',function(){
        $(this).children(".children").toggle();
    }).on('click','a',function(e) {
        e.stopPropagation();
   });
});
Rohan Kumar
  • 39,838
  • 11
  • 73
  • 103
  • @xr280xr - sorry, I confused it with .net, where returning false from an event handler is one way to terminate propagation. I've deleted my incorrect comment. – ToolmakerSteve Apr 05 '21 at 18:18
6

I stumbled upon this question, looking for another answer.

I wanted to prevent all children from triggering the parent.

JavaScript:

document.getElementById("parent").addEventListener("click", function (e) {
    if (this !== event.target) return;
    // Do something
});

jQuery:

$("#parent").click(function () {
    // Do something
}).children().on("click", function (e) {
    e.stopPropagation();
});
Daan
  • 2,584
  • 19
  • 37
  • The first part is similar to [xr280xr's] earlier answer, but using plain javascript. The second code snippet has the same limitation/flaw as the accepted answer (see comments there) - instead use the technique shown in first code snippet - see xr280xr's answer for how that better technique looks with jquery. – ToolmakerSteve Jul 24 '20 at 19:58
4

The answers here took the OP's question too literally. How can these answers be expanded into a scenario where there are MANY child elements, not just a single <a> tag? Here's one way.

Let's say you have a photo gallery with a blacked out background and the photos centered in the browser. When you click the black background (but not anything inside of it) you want the overlay to close.

Here's some possible HTML:

<div class="gallery" style="background: black">
    <div class="contents"> <!-- Let's say this div is 50% wide and centered -->
        <h1>Awesome Photos</h1>
        <img src="img1.jpg"><br>
        <img src="img2.jpg"><br>
        <img src="img3.jpg"><br>
        <img src="img4.jpg"><br>
        <img src="img5.jpg">
    </div>
</div>

And here's how the JavaScript would work:

$('.gallery').click(
    function()
    {
        $(this).hide();
    }
);

$('.gallery > .contents').click(
    function(e) {
        e.stopPropagation();
    }
);

This will stop the click events from elements inside .contents from every research .gallery so the gallery will close only when you click in the faded black background area, but not when you click in the content area. This can be applied to many different scenarios.

Gavin
  • 6,679
  • 3
  • 47
  • 71
2

The simplest solution is to add this CSS to the children:

.your-child {
    pointer-events: none;
}
Paul Roub
  • 35,848
  • 27
  • 79
  • 88
Pier
  • 9,372
  • 15
  • 57
  • 108
0

Or this:

$(document).ready(function(){
    $(".header").click(function(){
        $(this).children(".children").toggle();
    });
   $(".header a").click(function(e) {
        return false;
   });
});
user719004
  • 25
  • 2