30

I have a div with a link inside of it:

<div id="myDiv">
    <a href="http://www.lol.com">Lol</a>
</div>

Clicking the <div /> should go somewhere, but clicking the child <a /> should go to www.lol.com. I've seen from previous questions and the jQuery website that .stopPropagation prevents bubbling upwards, but how do I prevent a bubble downwards (isn't that what's necessary here?).

Community
  • 1
  • 1
atp
  • 30,132
  • 47
  • 125
  • 187

2 Answers2

48

Events only bubble up. So the click event handler for the a element is fired before the click event handler for the div. If you want the behaviour you describe, the you need to add a click event handler to the a element which stops propagation to the div.

$("#myDiv a").click( function(event) {
    event.stopPropagation();
} );

and keep whatever event handler you have on the div. This should allow the event to perform it's default action, and prevent the handler on the div being fired.

If you only want to prevent clicks on links then you can change your event handler for the div element

$("#myDiv").click( function( event ) {
    if( !$( event.target ).is( "a" ) )
    {
        // existing event handler
    }
} );
Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
Geoff
  • 3,129
  • 23
  • 11
  • 5
    Even though it will work, I respectfully disagree with this answer. As I said in my answer, you only need to check the `event.target` is the `
    ` element in it's click handler (using an `if` statement). There's no need to add another event handler to the `` element, it's extra handlers and extra work where it's not necessary.
    – Andy E Apr 28 '10 at 11:06
  • 3
    Yes, you can do if( $(event.target).is( "a" ) ) { /* code here */ } inside the div event handler. It was more an explanation as to how event bubbling works. There are instances where it might be easier or more efficient to add a couple of event handlers to the children, especially if there are multiple element types that would make the if condition more complicated. I shall include it in the answer. – Geoff Apr 28 '10 at 11:19
4

The problem was that clicking the anchor still triggered a click in your <div>. That's called "event bubbling".

In fact, there are multiple solutions:

Checking in the DIV click event handler whether the actual target element was the anchor → jsFiddle

$('#myDiv').click(function (evt) {
    if (evt.target.tagName != "A") {
        alert('123');
    }

    // Also possible if conditions:
    // - evt.target.id != "ancherComplaint"
    // - !$(evt.target).is("#ancherComplaint")
});

$("#ancherComplaint").click(function () {
    alert($(this).attr("id"));
});

Stopping the event propagation from the anchor click listener → jsFiddle

$("#ancherComplaint").click(function (evt) {
    evt.stopPropagation();
    alert($(this).attr("id"));
});

As you may have noticed, I have removed the following selector part from my examples:

:not(#ancherComplaint)

This was unnecessary because there is no element with the class .expandable-panel-heading which also have #ancherComplaint as its ID.

I assume that you wanted to suppress the event for the anchor. That cannot work in that manner because both selectors (yours and mine) select the exact same DIV. The selector has no influence on the listener when it is called; it only sets the list of elements to which the listeners should be registered. Since this list is the same in both versions, there exists no difference.

rvighne
  • 20,755
  • 11
  • 51
  • 73
Vijay
  • 8,131
  • 11
  • 43
  • 69