Issue regarding live event - javascript

I was just reading http://api.jquery.com/event.stopPropagation/
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
I was a bit confused with this statement, Can someone please explain me the same with some example?

Live method binds a handler to the document, and identifies which element triggered the event from the event.target property.
So the actual handler is at the top (in terms of hierarchy).
The stopPropagation stops the bubbling from going up the DOM hierarchy, but since the handler is at the top already (in the .live case) there is no upper place to bubble to ..
example attempt ..
- document
- div
- link
you bind a click event handler to the link (with the bind or click method).
When you click the link, the handler is triggered, but in addition the click event goes up the DOM until it reaches the document, and will also trigger click handlers bound to the div and document. (unless you use the .stopPropagation)
Alternatively if you use the .live method to bind the event handler, it will be bound to the document. If you now click the link, the event (which will not fire right away, since no handler is bound to it) will naturally go up the DOM (triggering the click handlers it encounters). Once it reaches the document it will trigger our own handler. But there is no upper to go, so the stopPropagation is useless at this point.

HTML:
<div id="outer">
<div id="inner">
<span>.live() version</span>
</div>
</div>
<div id="outer2">
<div id="inner2">
<span>.delegate() version</span>
</div>
</div>
JS:
$(function(){
$('#inner2').delegate('span', 'click', function(e){
e.stopPropagation(); // indeed, no alert!
});
$('span').live('click', function(e){
e.stopPropagation();
// we would expect the propagation to stop here, so no alert, right?
});
$('#outer2, #outer').click(function(){ alert("Don't reach me!"); });
});
Example: http://jsfiddle.net/knr3v/2/
.live() only does its magic once the event has already bubbled, so stopping the event from propagating is useless - it's too late, it has already reached the top of the tree and propagated...

Related

Need to get info from any element, which was clicked, but not from parent elements

Need to get info from any element, which was clicked.
Example:
<div>text1<section>text2</section></div>
and JS
$(function(){
$('body *').click(function(){
alert($(this).get(0).tagName.toLowerCase());
});
});
If I click text2, parent element throw alert too. I need only first alert from section. How I can block next alerts from all parent elements of section.
Use event.stopPropagation() to prevent the event from firing on the containing elements.
$(function(){
$('body *').click(function(e){
e.stopPropagation();
alert($(this).get(0).tagName.toLowerCase());
});
});
Just wanted to expand on Kooilnc answer - Using on with event delegation is another option.
Event delegation would be nice if you have an event listener bound before or after on a node that needs to listen to a click handler that has bubbled up. If you stopPropagation, this obviously would be an issue.
Here's a fiddle with a demo:
http://jsfiddle.net/ahgtLjbn/
Let's say a buddy of yours has bound an event listener to a node higher up in the DOM tree. He expects any events that bubble up to it, to be handled by his script.
Using event delegation, the event still bubbles up (so your buddies code will still fire), but it will only alert once (since we called e.stopPropagation).
Calling on without event delegation, or binding the event directly using click (which, under the hood, is just calling on) will prevent the event from bubbling, so your buddies code will never run.

Fire click event for only innermost element in jQuery

I'm trying to fire a click event on the innermost element in the HTML tree, but since there is a click even tied to its parent container, both events are fired, which is not what I need. I have fixed this before with stopPropagation(), but I can't seem to get it to work today.
jQuery('#parent li').click(function() {
jQuery(this).children('.contained').slideDown();
});
jQuery('.contained').click(function() {
Query(this).slideUp();
});
and let's say here is our HTML:
<ul id="parent">
<li>
click to show more
<p class="contained">click to hide</p>
</li>
</ul>
I believe this won't validate since it has a p contained within an li, but let's ignore that momentarily for simplicity's sake. How can I have the inner element slideUp() without have the parent click even trigger it to slideDown() immediately after?
return false to stop the bubbling:
jQuery('.contained').click(function() {
Query(this).slideUp();
return false;
});
Note that returning false also prevent the default behavior of the event.
Read more here.
Or use the event object's stopPropagation function:
jQuery('.contained').click(function(e) {
Query(this).slideUp();
e.stopPropagation();
});
The answer is to stop the propagation of the event. You can use stopPropagation and its twin, stopImmediatePropagation to do this or you can both stop propagation and prevent the default action by returning false from the handler. The stopPropagation method will prevent event bubbling, that is, the propagation of the event up the DOM tree. The stopImmdiatePropagation will do that but also prevent other handlers at the same level from firing. Returning false is equivalent to using stopPropagation and preventDefault on the event.
Two ways to do it, stop the propagation or combine the two click handlers and adjust code according to event.target
Target method:
jQuery('#parent li').click(function(event) {
var $tgt=jQuery(event.target)
if (!$tgt.is('.contained') ){
jQuery(this).children('.contained').slideDown();
}else{
$tgt.slideUp();
}
});

button click event triggering wrong event handler

I have a div display some titles of music which is clickable. When you click it it will show some more detail information. Then I also have a button in the clickable div. When I click the button. It won't call the function of the button but the function of the div? Is there a way to solve this? Thank you!
$("#myComList").append("<div id="+comListID+" class=listDiv> <p class=comTitle><? echo $row["compositionTitle"] ?>(<?echo $row["year"]?>)</p><button id="+comListID+"btn class=addNewArrBtn>Add new Arrangement</button> <p class=comOri>BY <? echo $row["OrigComposer"] ?></p> </div>");
$('#'+comListID).click(function() {
$(this).find("li").slideToggle('slow', function() {
});
$("#"+comListID+"btn").click(function(){
addNewArr(comListID);
});
It's called 'bubbling'. The button is inside the div so it's executing button then up the chain to div. Add event.stopPropagation() inside the button function.
$("#"+comListID+"btn").click(function(event){
event.stopPropagation();
addNewArr(comListID);
});
From jQuery documentation:
By default, most events bubble up from the original event target to
the document element. At each element along the way,
jQuery calls any matching event handlers that have been attached.
A handler can prevent the event from bubbling further up the document
tree (and thus prevent handlers on those elements from running) by
calling event.stopPropagation(). Any other handlers attached on the
current element will run however. To prevent that, call
event.stopImmediatePropagation(). (Event handlers bound to an element
are called in the same order that they were bound.)
http://api.jquery.com/on/
So you'd call event.stopPropagation() inside the button click handler, as to stop the div event from firing.
I believe I understand your question without seeing the code. The problem it sounds like stems from the click event bubbling or propagating up. Below is a sample of code to try and a link to a fiddle for you to test:
<div id="testDiv" onclick="alert('Stop Clicking Me!');">
<button type="button" onclick="function(e) { alert('You hit the button!'); e.stopPropagation(); }">Click Me!</button>
</div>
In this function, the:
e.stopPropagation();
prevents the click event from filtering up to its parent container (in this case "testDiv") and triggering its click event as well. You can test it and see for yourself in the jsfiddle below:
Test Fiddle
EDIT:
In your case:
$("#"+comListID+"btn").click(function(e){
addNewArr(comListID);
e.stopPropagation();
});
add the event parameter to the click function and stop it from propagating to the parent.
Hope this helps.

Direct vs delegation and bubbling vs capturing in jQuery

HTML
<div>
<span></span>
<span></span>
<span></span>
<span></span>
</div>
jQuery
$('div span').on('click', function(){
//direct - 1st method
});
$('div').on('click','span', function(){
//delegation - 2nd method
});
I have used both above method in my code. I know second method is better due to it has only got single handler. My problems are:
Is first method (direct) refers to the concept called event capturing? Is it an example for event capturing?
Is second method (delegation) refers to the concept called event bubbling? Is it an example for event bubbling?
It appears as though All jQuery event methods use Event Bubbling, not Event Capturing.
Therefore, both of your examples will use Event Bubbling.
There is an edge case with focus and blur events not bubbling in some browsers. In the affected browsers, Event Capturing is used for focus and blur events.
For reference, you can simply view the source. http://code.jquery.com/jquery.js
$('div span').on('click', function(){
//direct - 1st method
});
This event only attached the event handler to the spans inside Div that are currently present in the DOM.. i.e; if a new span element is added to the div , that span will not have a click event associated with it..
The first and second one are example's of Event Bubbling
There comes the concept of Event delegation where in the ancestor is given the event handler and it is delegated to the children..
The second example is an example of event delegation .
Wherein event is attached to the parent element..So all the span element's inside the div class are attached to the event handler ..
So if a new span element is added to the div , becoz the event is associated with the span's ancestor the event will fire in this case
This helps in cases
$('div').on('click','span', function(){
//delegation - 2nd method
});
I have no idea where event capturing is used in the jQuery library
Answers to your questions:
This isn't bubbling, capturing, or delegating. It's just adding an event listener directly to an element.
Yep, this is delegation that under the hood relies on clicks bubbling up.
Event bubbling and capturing are different implementations of the same concept, brought to you by Microsoft and Netscape, respectively. Both listening for events on parent elements. Note that they occur in a different order: capturing happens from the parent down to descendent, whereas bubbling happens the other way around.
More details and its history on PPK's website: http://www.quirksmode.org/js/events_order.html
Modern browsers support both capture and bubbling (bubbling is the default now), and you can specify which one you want to use when you use the native addEventListener:
element.addEventListener('click', function(){}, false); // bubble
element.addEventListener('click', function(){}, true); // capture
However, some events, such as focus, blur, scroll, mouseover, etc only are supported through capture phase events, so you MUST specify "true" when you use addEventListener.
Unfortunately, it looks like jQuery doesn't support delegation for all capture phase events, only focus and blur (see https://github.com/jquery/jquery/blob/ad032d3c7df04827989a4187117614c29bf3a4ad/src/event.js#L728).
The short answer: for delegation of capture-phase events other than focus and blur, you need to use the native addEventListener, not jQuery.

event.stopPropagation stops propagation of live events, although it should not

The documentation for says that event.stopPropagation shouldn't stop propagation of live events (http://api.jquery.com/event.stopPropagation). However it works just the opposite for me. Try this: http://jsfiddle.net/PSYg8. Clicking on the red Div should fire the live event attached to the html element.
What the documentation is telling you is that it is not possible to call stopPropagation from a live handler.
Because jQuery implements live events by listening to all events that propagate up to the <html> element and then seeing if the firing element matches your original selector, stopping propagation from a regular event handler on an element prevents the event from ever reaching the live handler.
Edit: If you're not clear on how DOM events and event propagation works, QuirksMode has a wonderful analysis of the capturing and bubbling models, and Microsoft has a great page that lets you visualize how event propagation works in the W3C, classic, and IE models.
You're swapping the items. Inside .live, you cannot use stopPropagation. So for example this does generate two alerts: http://jsfiddle.net/PSYg8/1/.
$(document).ready(function(){
$('html').live('click', function(){
alert('html');
event.stopPropagation();
});
$('div').click(function(event){
alert('div');
});
});
Inside .click (.bind), stopPropagation works seamlessly. It just stops the div event from bubbling up to the html element.
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
Meaning
$('html').live('click', function(e){
e.stopPropagation(); // does nothing
alert('html');
});
You misinterpreted the documentation. When you stop propagation on the click event it does not bubble upto the live event.

Categories