8

I will have couples scenario here. Please help me

Here is the base case: http://jsfiddle.net/2zsLy/9/

When I click Click Me, both alert box and Another Paragraph come out. This is expected since the click event bubble up to the parent container, which is body. Now start my questions

1) http://jsfiddle.net/2zsLy/10/

How come adding return false to my live.click does not stop the click event from bubble up. From the example, the live.click bubble up and trigger the alert box. I thought the documentation said that return false will stop the live event from bubble.

2) http://jsfiddle.net/2zsLy/11/

Now, I change the click event in body to live.click and it fix the problem -> the click event does not bubble up (hence no alert box is shown). Why does live.click work and click does not.

3) http://jsfiddle.net/2zsLy/13/

I think the documentation clearly said that calling event.stopPropagation() will not stop the bubbling up from occurring, well I just did. I use event.stopPropagation() expecting that it will still trigger my alert box, but it does not. Why?

NOTE: for the answer of the first two question, see justkt answers. For the answer to the last question, see Squeegy answer and his reply.

Thang Pham
  • 38,125
  • 75
  • 201
  • 285

2 Answers2

11

Answers to your questions can be found in the event.stopPropagation() docs.

With regards to live('click') versus 'click' and bubbling:

Since the .live() method handles events once they have propagated to the top of the document, it is not possible to stop propagation of live events. Similarly, events handled by .delegate() will always propagate to the element to which they are delegated; event handlers on any elements below it will already have been executed by the time the delegated event handler is called.

So what you are seeing is expected behavior. live('click') won't stop bubbling. The same is true of the now-preferred .delegate().

This answer describes extensively the problems of stopping propegation when using .live. See also the .live() documention:

The event bubbles up until it reaches the root of the tree, which is where .live() binds its special handlers by default.

  • As of jQuery 1.4, event bubbling can optionally stop at a DOM element "context".

With regards to stopPropagation itself:

Kill the bubbling on the click event.

So stopPropagation() should prevent bubbling wherever return false; will, although not where it won't. It is preventDefault() that will not prevent bubbling. return false; is effectively stopPropagation() and preventDefault().


In response to each jsfiddle example.

1) http://jsfiddle.net/2zsLy/10/

return false; will not prevent events bound using live or delegate from bubbling up. The documentation explicitly says this about all bubbling, whether done with return false; or with stopPropagation(). So what happens is

  1. Click on <p>
  2. Click bubbles to <body>, where body.click() is triggered
  3. Click bubbles to document root, where it matches $(event.target).closest('p'); and so live('click') is invoked
  4. Return false happens, but body handler was invoked at step 2

2) http://jsfiddle.net/2zsLy/11/

In this case the event gets to the same spot (document root) and the return false stops the propagation to the further event bound via live, which is on the body.

  1. Click on <p>
  2. Click bubbles to <body>, but since body's handler is attached via live it is not invoked yet
  3. Click bubbles to document root, where it matches $(event.target).closest('p'); and so live('click') is invoked
  4. Return false happens
  5. live('click') is not invoked on the body due to the return false occurring.

3) http://jsfiddle.net/2zsLy/13/

stopPropagation() is explicitly used to prevent bubbling, although it has the same restrictions return false; does - so it won't prevent it in the case of a live('click') event if there are click handlers bound via bind.

Community
  • 1
  • 1
justkt
  • 14,610
  • 8
  • 42
  • 62
  • I dont think you answer my question at all. U just cite the documentation just none that I do not know. For each scenerio, I include jsfiddle to demonstrate my question. Please refer to them. – Thang Pham May 03 '11 at 18:21
  • @Harry - I have edited my answer to address each jsfiddle example. – justkt May 03 '11 at 18:36
  • Thank you very much. Your answer on `1` and `2` give great deal of help to me. However, for `3`, not to say that you are wrong, but here is the quote from jQuery site `To stop further handlers from executing after one bound using .live(), the handler must return false. Calling .stopPropagation() will not accomplish this.` From above, `Squeegy` makes an answer and some comment about `3`, do u agree with his answer for `3`, justkt? – Thang Pham May 03 '11 at 18:46
  • 1
    @Harry - I believe the section you've quoted refers to other handlers on the same DOM object (so another handler bound to `p`), which has to be stopped using `return false` or `stopImmediatePropegation` (which implicitly calls `stopPropegation`). [See this bug report](http://bugs.jquery.com/ticket/7353) when it was broken for why I think that. I think Squeegy is right. – justkt May 03 '11 at 18:56
  • Thank you. Just out of curiosity, what is the answer for the bug report you send me. The comment said u event.stopImmediatePropagation(), but I try it and it does not work. Here is the jsfiddle: http://jsfiddle.net/6krK5/4/ – Thang Pham May 03 '11 at 19:07
  • 2
    @Harry - you set jQuery to 1.4.3. Set it to 1.4.4 or after and see that the bug was fixed. Note the one comment in that bug report: `Unfortunately calling stopImmediatePropagation() doesn't work in 1.4.3 for live handlers, but this has already been fixed and will work once 1.4.4 comes out.` If you advance the version, you'll see that's true. – justkt May 03 '11 at 19:24
  • Thanks justkt, great answer. Just wanted to let you know you spelled stopPropagation() incorrectly a couple times in this answer. – nerdburn Oct 27 '12 at 23:53
2
  1. Live events ALWAYS happen after bind events (like calling click(fn)). So return false does nothing here because $("body").click() already happened. This is due to bubbling. The click happens on each parent of the element you clicked, triggering every click event. Only when it bubbles up to the root document, does it trigger any live events.

  2. In this example, you have 2 live events. So the event bubbles up to the document, and jQuery starts running any live events it finds that match your click. When it gets a return false it stops running any other live events. And live events declared first, run first. So you get the new paragraph, but nothing else since the alert was added to the live event stack AFTER the p live click.

  3. It wont stop propogation for bind events, but the event argument is actually a jQuery event wrapper object, and I believe it knows about live. So it has a similar effect as returning false, it prevents the document click handler from executing any additional live events.

Alex Wayne
  • 178,991
  • 47
  • 309
  • 337
  • Great answer on `1` and `2`. I am not sure I understand your answer for `3`. So `event.stopPropagation()` did not stop the propagation, what stop the propagation, Squeegy? – Thang Pham May 03 '11 at 18:31
  • 3
    It stopped lateral propagation, not vertical. `$('p').live('click', fn)` binds a `click` handler to document. Multiple live events from a single click can happen because that click handler loops through all registered live events and tries to match the selector you provided to the element that started the event. If there is a match, it runs your function. `event.stopPropagation()` tells jQuery to abort that loop early. So you are not stopping the bubbling of the event, you are stopping the `document`'s click handler from finding any additional elements to `click`. – Alex Wayne May 03 '11 at 18:35