red house 87
red house 87

Reputation: 2415

Event propagation issue

I have a series of click events which are causing me some propagation issues. The data for this container is loaded in via ajax hence the body on click method. Here's the code I have:

$(function () {
    $("body").on("click","#top-div",function(){
        console.log("top event");
    });

    $("body").on("click","#middle-div",function(e){
        e.stopPropagation();
    });

    $("body").on("click","#bottom-div",function(){
        console.log("bottom event");
    });
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
  top
    <div id="middle-div">
      middle
        <div id="bottom-div">
          bottom
        </div>
    </div>
</div>

The top div has an event which the middle one needs to not inherit hence the stopPropagation(). However the bottom one needs to have an event of its own but the stopPropagation() from the middle one is stopping it from executing the event (if I remove the stop propagation the bottom event triggers but coincidentally so does the top)

How can I get around this bubbling issue?

Upvotes: 1

Views: 581

Answers (3)

Geeky
Geeky

Reputation: 7496

Instead of attaching event to every div. You can consider doing it as follows check this snippet

$(document).ready(function() {
  $("body").on("click", "div", function(event) {
    console.log(event.currentTarget.id + "event");
    if (event.target.id === "middle-div") {
      event.stopPropagation()
    }
  });


});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
  hello
  <div id="middle-div">
    hi
    <div id="bottom-div">
      bott-mid-v
    </div>
  </div>
</div>

Hope it helps

Upvotes: 0

Maciej Sikora
Maciej Sikora

Reputation: 20152

Bubbling works from most nested element to tree root, I think You misunderstanding it in some way. So for example click in bottom-div will:

call event on bottom-div --> call event on middle-div --> call event on top-div.

As I understand the need You want to some how check what div was clicked, so to have control on it just create single event and check clicked target like that:

$("body").on("click","#top-div",function(e){

   if ( e.target.id ==='top-div'){
     //click in top div
   }

   if ( e.target.id ==='middle-div'){
     //click in middle div
   }

   if ( e.target.id ==='bottom-div'){
     //click in bottom div
   }



});

In this proposition You know exactly which div was clicked, but it will always be the most nested one, so target will be middle-div only when will be clicked part of middle-div which is not bottom-div, it will be for example padding space, the same is with top-div it will be target only if click will be in space without child elements.

More about event bubbling You can find in http://maciejsikora.com/standard-events-vs-event-delegation/.

Upvotes: 0

lonesomeday
lonesomeday

Reputation: 237885

I think what you want to happen is that the propagation is only stopped if it originated from the middle div; if it originated from the bottom div you want the event to bubble all the way to the top.

You need to call stopPropagation conditionally. If the event did not originate on or inside #bottom-div, you want to call it. You can test for this using closest:

if (!$(e.target).closest('#bottom-div').length) {
    e.stopPropagation();
}

It is better to use closest for this, rather than testing the element's id directly, because with closest it will continue to work as expected even if there are other elements (a or em, for example) within the various divs.

$(function () {
    $("body").on("click","#top-div",function(){
        console.log("top event");
    });

    $("body").on("click","#middle-div",function(e){
        if (!$(e.target).closest('#bottom-div').length) {
            e.stopPropagation();
        }
    });

    $("body").on("click","#bottom-div",function(){
        console.log("bottom event");
    });
  });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="top-div">
  top
    <div id="middle-div">
      middle
        <div id="bottom-div">
          bottom
        </div>
    </div>
</div>

Upvotes: 2

Related Questions