243

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>
0

7 Answers 7

450

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.

Sign up to request clarification or add additional context in comments.

7 Comments

if it helps somebody, I replaced $(".header a") with $(".header *") and got any child selected (div, forms, input, etc).
e.stopPropagation(); must be written at first line, unless it doesn't work!
sadly this method preventing the rel configured lightbox to function
The answer below by xr280xr is much better, as it doesn't interfere with possible events of the children.
You create more problems than you solve. Imagine third party plugins listening to click event on document element. They will never know about those clicks. See the comment about lightbox.
|
127

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();
});

9 Comments

To me this is a more elegant solution since you don't have to add an explicit preventDefault() to every child element.
And it works if you have independent events on child unlike the accepted answer. Definitely cleaner and better solution
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. A workaround is to replace it with this, as suggested in another answer.
This is a cleaner solution than setting an extra listener to just catch clicks.
this code worked better for me` var target=$(e.target); if(!target.is("span")) return;`
|
25

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();
   });
});

1 Comment

@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.
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();
});

1 Comment

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.
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.

Comments

3

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

.your-child {
    pointer-events: none;
}

2 Comments

I needed this for the unwanted font tag added by Wordpress and it worked for me
This is easiest way I found
0

Or this:

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

3 Comments

@Halcyon991 e gets passed in either way through arguments, e is just a reference
@qodeninja Yeah, but a needless character addition if it's not used.
No point adding return false to link, it should be clickable.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.