27

So I have the following scenario:

<div id="block">
Sample text.
<a href="#">Anchor link</a>
</div>

<script type="text/javascript">
    $("#block").click(function() { alert('test'); });
</script>

When I click anywhere inside the div, I'm getting the 'test' alert. But, I want to prevent that from happening when I click on the "Anchor link". How can I implement that?

Thanks

Elie
  • 6,915
  • 7
  • 31
  • 35

5 Answers5

31

You can stop the clicks from bubbling up from links with an additional handler, like this:

$("#block a").click(function(e) { e.stopPropagation(); });

The the alternative we were discussing in comments:

$("#block").delegate('a', 'click', function(e){ e.stopImmediatePropagation(); })
           .click(function() { alert('test'); });​

This would prevent any child links from bubbling up (well, not really, but their handlers from executing), but not create a handler for each element, this is done via .stopImmediatePropagation().

Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • 4
    It feels a bit "overkill" to add a click handler to each link just to prevent event propagation (of course it depends on the number of links). But this is a good way to prevent event propagation for any specific element. – Felix Kling Oct 05 '10 at 13:46
  • @Felix - If there are many links I'd take a different approach entirely with a set of `.delegate()` handlers :) (you could use a delegate version of the above *before* the other click handler as well). – Nick Craver Oct 05 '10 at 13:48
  • I just tried with `delegate()` and it does not work for me: http://jsfiddle.net/cxcfA/. I assume because the event already bubbled up. Or do you mean something else? – Felix Kling Oct 05 '10 at 13:57
  • @Felix - `e.stopImmediatePropagation();` ;) http://jsfiddle.net/nick_craver/cxcfA/1/ – Nick Craver Oct 05 '10 at 13:59
  • Very nice :) Good one! You always seem to have an answer ;) – Felix Kling Oct 05 '10 at 14:01
  • There's a bug though in jQuery, the delegate function doesn't return the object. – Elie Oct 05 '10 at 15:09
16

This is what you need: http://api.jquery.com/event.target/ .

Just compare to check if the element was triggered by the element you want or one of its children.

Alexander
  • 23,432
  • 11
  • 63
  • 73
Alin Purcaru
  • 43,655
  • 12
  • 77
  • 90
9

You can test which node was clicked with the target property of the event object:

$("#block").click(function(event) { 
    if(event.target.nodeName != 'A') {
        alert('test');
    }
});

I suggest to read Event Properties from quirksmode.org.

Felix Kling
  • 795,719
  • 175
  • 1,089
  • 1,143
4
$("#block").click(function(event) {
    if($(event.target).attr('id') == $(this).attr('id'))
    {
        alert('test');
    }
});
methodin
  • 6,717
  • 1
  • 25
  • 27
0

Here is a demo (jsfiddle) with a forms and two fields:

<div id="container">
    <form>
        <div class="field">
            <input id="demo" type="text" name="demo" />
        </div>
        <div class="field">
            <input id="demo2" type="text" name="demo2" />
        </div>
    </form>
</div>

The code looks like this:

$(document).ready(function() {
    $('#container').click(function(evt) {
        if(this == evt.target) {
            console.log('clicked container',evt.target);
            $('#demo').focus();
        } else {
            console.log('clicked child -> ignoring');
        }
    });

    $('.field').click(function(evt) {
        if(this == evt.target) {
            console.log('clicked field div',evt.target);
            $(this).find('input').focus();
        } else {
            console.log('clicked child -> ignoring');
        }
    });
});

You can click the container that contains the form to set the focus on the first input field or behind the input field to set the focus into it.

If you click into the field, then the click will be ignored.

The code above works since jQuery assigns the DOM node to this before calling event handlers, so you can easily check whether the current event was published by the DOM node by checking

this == evt.target

CSS:

#container {
    width: 600px;
    height: 600px;
    background: blue;
}

.field {
    background: green;
}
Aaron Digulla
  • 321,842
  • 108
  • 597
  • 820