3
<!DOCTYPE html>
<html>

<head>

<script src="jquery-2.1.1.min.js" type="text/javascript"></script>

</head>

<body>

<div id="outer">
    <div id="inner">
    </div>
</div>

<script type="text/javascript">

$("#outer").on("myevent", function(event) { 
    alert(event.target.id);
    event.stopPropagation();
    return false;
});

$("div").trigger("myevent");

</script>

</body>

</html>

In the code above I expect the event myevent to be handled once by outer div. But I see two alerts: outer and then inner. Why stopPropagation does not work here and how do I prevent propagating custom events to children?

EDIT: I want to trigger event globally, like $("div").trigger("myevent"); but I want to handle it only there where I subscribed to it.

rmflow
  • 4,445
  • 4
  • 27
  • 41

3 Answers3

3

Instead of using event.stopPropagation() on $('#outer').on('myevent'), you need to use it on every div element in a separate handler:

$("#outer").on("myevent", function(event) { 
    console.log(event.target.id);
    return false;
});
$('div').on('myevent', function(event) { // or $('*').on('myevent', ...
    event.stopPropagation();
});

$("div").trigger("myevent"); // only logs 'outer'

http://jsfiddle.net/mblase75/z7NQy/

Blazemonger
  • 90,923
  • 26
  • 142
  • 180
2

$("div").trigger("myevent"); is equivalent to:

$("div").each(function() {
    $(this).trigger("myevent");
});

because jQuery automatically loops over all the elements that match the selector. So it's triggering the event on the inner and outer DIVs separately.

When it triggers it on the inner DIV, there's no handler there, so nothing stops the event from bubbling to the outer DIV.

To stop this from happening, you should be more specific about the element you're triggering on:

$("#outer").trigger("myevent");
Barmar
  • 741,623
  • 53
  • 500
  • 612
  • I want to trigger event without knowing who handles it. Otherwise I could just write a function and pass div id to it instead of using events. – rmflow Jul 09 '14 at 13:01
  • 1
    You could send it to `#inner`. It will then be handled by `#outer` when it bubbles out. – Barmar Jul 09 '14 at 13:08
  • yes, I could handle event in `#inner` and it would not be bubbled up, but this is not exactly what I want (I need to do something with the `target` in the handler). Seems, my question is completely invalid due to weak understanding of javascript events. – rmflow Jul 09 '14 at 13:15
  • 1
    It sounds like you may want to use the event capture model for your event. Trigger the event on the document, and it will propagate down the DOM hierarchy, and get caught by `#outer` when it gets there. See http://stackoverflow.com/questions/4616694/what-is-event-bubbling-and-capturing – Barmar Jul 09 '14 at 13:18
  • @Barmar That answer says that the event capture model isn't supported by all browsers. – Blazemonger Jul 09 '14 at 13:31
1

You are getting two alerts because you are triggering myevent on div and hence it will apply to all div available in html. In this case you have inner and outer div which triggers myevent one by one.

To trigger myevent on outer div use :

$("div#outer").trigger("myevent");

Demo

Bhushan Kawadkar
  • 28,279
  • 5
  • 35
  • 57
  • Qualifying an ID-based selector is not only pointless, as the id is in a fast look-up, but actually slows the selector down. Just use `#outer` – iCollect.it Ltd Jul 09 '14 at 13:18
  • @TrueBlueAussie True, although it's not pointless if there's a possibility that `#outer` is a different type of DOM element. – Blazemonger Jul 09 '14 at 13:37
  • @Blazemonger: if the id is known, and it obviously must be unique, it is more likely to cause problems if the same ID is reused across pages for different elements. My point stands. – iCollect.it Ltd Jul 09 '14 at 13:40