stopPropagation and live() method. What am I missing?
Asked Answered
I

1

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?

Infatuate answered 19/12, 2012 at 9:53 Comment(3)
Why not just $('a').on( "click", function() {alert("link"); return false;} );?Christachristabel
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.Hosmer
Seems like it's because for ul and ul li you also used live. If you change them to bind they're both called.Sogdiana
O
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);
    }
}
Oppen answered 19/12, 2012 at 9:57 Comment(5)
It's not working in 1.4.3, anyway I downvoted because 90% of your post is misguided that live is somehow different from delegationSantonin
@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.Oppen
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. jsfiddle.net/PHvVhSantonin
@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.Oppen
Thanks for all responses. I thought I might be missing something, but it turns out depending on jquery ver. same method is working different.Infatuate

© 2022 - 2024 — McMap. All rights reserved.