240

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,751
  • 1
  • 14
  • 21
John
  • 21,047
  • 43
  • 114
  • 155

7 Answers7

447

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
  • 623,446
  • 136
  • 1,297
  • 1,155
125

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
  • 12,621
  • 7
  • 81
  • 125
  • 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
  • I used this target method on a mobile side nav to enable closing the menu when clicked outside of the nav. The problem I had was clicking inside the menu closed the nav. Oh no! This solved that too! – jottin Jun 27 '22 at 18:36
  • This will not work if you have other elements inside of header that SHOULD be handled by the header click event. The event.target will be whatever element was directly under the cursor. Thus the event will not fire. – johnw182 Jan 23 '23 at 19:56
24

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
  • 40,431
  • 11
  • 76
  • 106
  • @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
7

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,680
  • 20
  • 39
  • 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
  • 7,544
  • 4
  • 52
  • 72
3

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

.your-child {
    pointer-events: none;
}
Paul Roub
  • 36,322
  • 27
  • 84
  • 93
Pier
  • 10,298
  • 17
  • 67
  • 113
0

Or this:

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