Here is a jsfiddle using POJS showing that return false;
doesn't stop the event's propagation: /
Here is another using jQuery showing that return false;
does stop the event's propagation: /
Edit: The one explaining to me why jQuery does this - differing from the original behavior intentionally - (and where in the code) gets the answer.
Here is the code (long, but very easy to read):
HTML for both versions:
<div id="parent1"> <div id="child1"><a href="#" id="a1">child1</a></div> </div> <div id="parent2"> <div id="child2"><a href="#" id="a2">child2</a></div> </div> <div id="parent3"> <div id="child3"><a href="#" id="a3">child3</a></div> </div>
POJS:
document.getElementById( 'child1' ).onclick = function( e ) { console.log( 'child1' ); e.preventDefault(); }; document.getElementById( 'parent1' ).onclick = function( e ) { console.log( 'parent1' ); }; document.getElementById( 'child2' ).onclick = function( e ) { console.log( 'child2' ); return false; }; document.getElementById( 'parent2' ).onclick = function( e ) { console.log( 'parent2' ); }; document.getElementById( 'child3' ).onclick = function( e ) { console.log( 'child3' ); e.stopPropagation(); }; document.getElementById( 'parent3' ).onclick = function( e ) { console.log( 'parent3' ); };
jQuery version:
$( '#child1' ).click( function( e ) { console.log( 'child1' ); e.preventDefault(); }); $( '#parent1' ).click( function( e ) { console.log( 'parent1' ); }); $( '#child2' ).click( function( e ) { console.log( 'child2' ); return false; }); $( '#parent2' ).click( function( e ) { console.log( 'parent2' ); }); $( '#child3' ).click( function( e ) { console.log( 'child3' ); e.stopPropagation(); }); $( '#parent3' ).click( function( e ) { console.log( 'parent3' ); });
Here is a jsfiddle using POJS showing that return false;
doesn't stop the event's propagation: http://jsfiddle/Ralt/Lz2Pw/
Here is another using jQuery showing that return false;
does stop the event's propagation: http://jsfiddle/Ralt/D5Mtg/
Edit: The one explaining to me why jQuery does this - differing from the original behavior intentionally - (and where in the code) gets the answer.
Here is the code (long, but very easy to read):
HTML for both versions:
<div id="parent1"> <div id="child1"><a href="#" id="a1">child1</a></div> </div> <div id="parent2"> <div id="child2"><a href="#" id="a2">child2</a></div> </div> <div id="parent3"> <div id="child3"><a href="#" id="a3">child3</a></div> </div>
POJS:
document.getElementById( 'child1' ).onclick = function( e ) { console.log( 'child1' ); e.preventDefault(); }; document.getElementById( 'parent1' ).onclick = function( e ) { console.log( 'parent1' ); }; document.getElementById( 'child2' ).onclick = function( e ) { console.log( 'child2' ); return false; }; document.getElementById( 'parent2' ).onclick = function( e ) { console.log( 'parent2' ); }; document.getElementById( 'child3' ).onclick = function( e ) { console.log( 'child3' ); e.stopPropagation(); }; document.getElementById( 'parent3' ).onclick = function( e ) { console.log( 'parent3' ); };
jQuery version:
$( '#child1' ).click( function( e ) { console.log( 'child1' ); e.preventDefault(); }); $( '#parent1' ).click( function( e ) { console.log( 'parent1' ); }); $( '#child2' ).click( function( e ) { console.log( 'child2' ); return false; }); $( '#parent2' ).click( function( e ) { console.log( 'parent2' ); }); $( '#child3' ).click( function( e ) { console.log( 'child3' ); e.stopPropagation(); }); $( '#parent3' ).click( function( e ) { console.log( 'parent3' ); });
- I wonder if the return false is being picked up by jQuery's event handling and stops the propagation there... – Ben Everard Commented May 4, 2012 at 15:52
- If that is so, I'd like to see where :-) Also, why would it be doing this? – Florian Margaine Commented May 4, 2012 at 15:52
- Ah, this might be it. Go to the jQuery source (code.jquery./jquery-1.7.2.js), search for 'event.stopPropagation', this happens just after a condition checking if a returned value is false. – Ben Everard Commented May 4, 2012 at 15:55
-
Strange that
e.stopPropagation()
is the only method that works for your POJS example. – Rory McCrossan Commented May 4, 2012 at 15:58 -
1
And from the documentation (second to last paragraph under The event handler and its environment): "Returning
false
from an event handler will automatically callevent.stopPropagation()
andevent.preventDefault()
." – Anthony Grist Commented May 4, 2012 at 15:58
1 Answer
Reset to default 8On line 3331 of version 1.7.1, in jQuery.event.dispatch
:
ret = ( (jQuery.event.special[ handleObj.origType ] || {}).handle || handleObj.handler )
.apply( matched.elem, args );
if ( ret !== undefined ) {
event.result = ret;
if ( ret === false ) {
event.preventDefault();
event.stopPropagation();
}
}
A lot of packaging has happened before this line, but basically, it runs the handler function (either a raw function, or the handler
memeber function of a handlerObject
) using apply
. If the result of that call is false, it does preventDefault
and stopPropagation
.
This is mentioned in the documentation for on()
:
Returning
false
from an event handler will automatically callevent.stopPropagation()
andevent.preventDefault()
.
As for why they did it? I don't know, as I'm not not the jQuery design team, but I assume it's just because return false
is a lot quicker to type than event.preventDefault(); event.stopPropagation();
. (And if jQuery isn't about making sure you have less to type, I'm not sure what it's about.)
I don't believe the return value of an event handler is ever actually used anywhere in POJS (someone correct if that's wrong!). Thus, jQuery can safely have a return
statement cause side effects in a handler (since returning false in a POJS handler is meaningless, no POJS functionality is harmed).