6

I've read jQuery doc and I know that there's no point in using stopPropagation() if I use live() to bind event to elements, as the event with live() binds to document node so the event has already spred up. Said so, I figured nex code would alert 3 times,as stopPropagation doesn't stop anything:

<ul style="border:red solid 1px;">
    <li style="padding:10px; border:blue solid 1px;">
        <p style="border:green solid 1px;"><a href="#">link</a></p>
    </li>
    <li style="padding:10px; border:blue solid 1px;">
        <p style="border:green solid 1px;">no link</p>
    </li>
</ul>

<script type="text/javascript">
    $('a').live( "click", function( e ) {alert("link");e.stopPropagation()} );
    $('ul').live( "click", function( e ) {alert("ul");} );
    $('ul li').live( "click", function( e ) {alert("li");} );
</script>

When I click link I expected and alert of "li" and "ul", however stopPropagation is stopping the other events when it was supposed to be useless. What am I missing?

James Allardice
  • 164,175
  • 21
  • 332
  • 312
Barleby
  • 618
  • 2
  • 9
  • 20
  • Why not just `$('a').on( "click", function() {alert("link"); return false;} );`? – Morpheus Dec 19 '12 at 09:58
  • Your code works as expected if i click on the exact link. I do not see the ul and li alerts. If i click on the space next to the actual link, i see the other two alerts. You might want to set widths to the elements so that you do not see this behavior. – Ravi Y Dec 19 '12 at 10:02
  • Seems like it's because for ul and ul li you also used `live`. If you change them to `bind` they're both called. – Andy Dec 19 '12 at 10:02

1 Answers1

6

As per documentation stopPropagation() does not work in live() as expected as live() only executes the event after it already bubbled up to the document.

However, if you are using jQuery 1.4.3 or later stopPropagation() started working.

live() was re-written several times since 1.4.3.
The live() documentation lists a lot of reasons why using other binding methods instead is preferred. It seems though that the information in the documentation refers to the 1.4.1 behaviour and doesn't seem to be 100% in sync with the actual current behaviour.

For example looking at the 1.7.1 Source which added on() it shows live() is using on():

live: function( types, data, fn ) {
    jQuery( this.context ).on( types, this.selector, data, fn );
    return this;
}

DEMO - Using your code and live in jQuery 1.4.1 - stopPropagation is not working, as expected

DEMO - Using your code and live in jQuery 1.4.3 - stopPropagation is now working

Summary

live() was re-written in 1.4.3. I assume due to delegate() having been added then.
live() has continuesly been updated with each version of jQuery as improvements were added.

In general to prevent any surprising results with live() it is better to follow the guidelines from the documentation and use the suggested methods for a given version of jQuery:

$(selector).live(events, data, handler);                // jQuery 1.3+
$(document).delegate(selector, events, data, handler);  // jQuery 1.4.3+
$(document).on(events, selector, data, handler);        // jQuery 1.7+

For completness I have added the live() source extract for 1.4.1 and 1.4.3 below.

1.4.1 source

live: {
    add: function(proxy, data, namespaces, live) {
        jQuery.extend(proxy, data || {});

        proxy.guid += data.selector + data.live;
        data.liveProxy = proxy;

        jQuery.event.add(this, data.live, liveHandler, data);

    },

    remove: function(namespaces) {
        if (namespaces.length) {
            var remove = 0,
                name = new RegExp("(^|\\.)" + namespaces[0] + "(\\.|$)");

            jQuery.each((jQuery.data(this, "events").live || {}), function() {
                if (name.test(this.type)) {
                    remove++;
                }
            });

            if (remove < 1) {
                jQuery.event.remove(this, namespaces[0], liveHandler);
            }
        }
    },
    special: {}
}

1.4.3 source

live: {
    add: function(handleObj) {
        jQuery.event.add(this, liveConvert(handleObj.origType, handleObj.selector), jQuery.extend({}, handleObj, {
            handler: liveHandler,
            guid: handleObj.handler.guid
        }));
    },

    remove: function(handleObj) {
        jQuery.event.remove(this, liveConvert(handleObj.origType, handleObj.selector), handleObj);
    }
}
Nope
  • 22,147
  • 7
  • 47
  • 72
  • It's [not working in 1.4.3](http://jsfiddle.net/WA9as/), anyway I downvoted because 90% of your post is misguided that `live` is somehow different from delegation – Esailija Dec 19 '12 at 10:16
  • @Esailija: I have added DEMO's showing it work in 1.4.1 and a comment regarding the the change in 1.4.3. In 1.4.3 `live()` was re-written, most likely due to the fact `delegate()` was added then. `live()` was added in 1.4.1 in which `stopPropagation()` did not work as expected. In 1.4.3 `delegate()` was added superceeding `live()`. I assume that is why jQuery `live()` was re-written with every release if an improvement was available. For convinience I also added the source for live in 1.4.1 and 1.4.3. – Nope Dec 19 '12 at 10:18
  • This behavior is still weird and unintuitive, they are all bound to `document` and only handled on `document`, only `e.stopImmediatePropagation` *should* have an effect. For example, this should be equivalent, yet it isn't. http://jsfiddle.net/PHvVh/ – Esailija Dec 19 '12 at 10:21
  • @Esailija: I totally agree. It is strange. I also couldn't find anything in the documentation for `live()` regarding the changes of live throughout the versions, making some of the bullet points the documentation raises on what doesn't work in `live()` redundant and confusing. – Nope Dec 19 '12 at 10:24
  • Thanks for all responses. I thought I might be missing something, but it turns out depending on jquery ver. same method is working different. – Barleby Dec 19 '12 at 12:17