I have a dl list of dd items. Each dd item has a listener attached to it (see below) so if it is clicked on I can rebuild the page and change some stuff. Each of these dd items also have a checkbox within them though which I would like to be excluded from that listener (so it can be picked up by another listener).
The problem that is occuring is whenever I click anywhere in the dd it will apply the dd listener, not the checkbox listener even if I clicked on the checkbox. Is there a way to distinguish what exactly was clicked without setting up divs inside the dd and applying listeners individually?
Example HTML Code:
<dl>
<dd class="class1 class2 class3">Some text and stuff
<input type="checkbox" class="class1 checkBox">
</dd>
</dl>
Example jQuery Code:
$("class1.checkbox").live("click", function() {
//Do some other, completely different, cool stuff
//console.log($(this).parent().attr("id"));
console.log("test");
});
$("dd.class1.class2").live("click", function () {
//Do some cool stuff
});
You need to stop the event bubbling.
$(".class1:checkbox").click(function(e) {
alert('clicked checkbox');
e.stopPropagation();
});
$("dd.class1.class2").click(function () {
alert('clicked dd');
});
http://api.jquery.com/event.stopPropagation/
The concept of "bubbling up" is like if you have a child element with a click event and you don't want it to trigger the click event of the parent. You could use event.stopPropagation().
event.stopPropagation() basically says only apply this click event to THIS CHILD NODE and don't tell the parent containers anything because I don't want them to react.
Event Capturing:
| |
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------
Event Bubbling:
/ \
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------
If you are using live() or delegate() you will need to return false;, though it may not work. Read the quote below.
Per JQuery docs:
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 propagate
to the elements to which they are delegated; event handlers bound on
any elements below it in the DOM tree will already have been executed
by the time the delegated event handler is called. These handlers,
therefore, may prevent the delegated handler from triggering by
calling event.stopPropagation() or returning false.
A good resource: http://fuelyourcoding.com/jquery-events-stop-misusing-return-false/
$(":checkbox").live("click", function(e) {
e.stopPropagation();
//Do some other, completely different, cool stuff
//console.log($(this).parent().attr("id"));
alert("test");
});
$("dd.class1.class2").live("click", function (e) {
e.stopPropagation();
//Do some cool stuff
alert("test2");
});
http://jsfiddle.net/PsaHQ/4/
Ok, you've got a bunch of little problems adding up to a big one here.
Your first selector has 2 issues in it. Look at the updated selector below (and notice the capitalization):
$(".class1.checkBox").live("click", function() {
//Do some other, completely different, cool stuff
console.log("test");
return false; //added.
});
If you want to stop the event from bubbling to the next jquery listener, just return false.
Just bind the click event to the dd and check the target delegate appropriately
$("dd.class1.class2").live("click", function (event) {
if($(event.target).is(":checkbox"))
{
console.log("put checkbox func here");
}else{
console.log("put div func here");
}
});
Working Example:
http://jsfiddle.net/QWLpd/1/
Related
They seem to be doing the same thing...
Is one modern and one old? Or are they supported by different browsers?
When I handle events myself (without framework) I just always check for both and execute both if present. (I also return false, but I have the feeling that doesn't work with events attached with node.addEventListener).
So why both? Should I keep checking for both? Or is there actually a difference?
(I know, a lot of questions, but they're all sort of the same =))
stopPropagation prevents further propagation of the current event in the capturing and bubbling phases.
preventDefault prevents the default action the browser makes on that event.
Examples
preventDefault
$("#but").click(function (event) {
event.preventDefault()
})
$("#foo").click(function () {
alert("parent click event fired!")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
<button id="but">button</button>
</div>
stopPropagation
$("#but").click(function (event) {
event.stopPropagation()
})
$("#foo").click(function () {
alert("parent click event fired!")
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
<button id="but">button</button>
</div>
With stopPropagation, only the button's click handler is called while the div's click handler never fires.
Where as if you use preventDefault, only the browser's default action is stopped but the div's click handler still fires.
Below are some docs on the DOM event properties and methods from MDN:
event.cancelBubble
event.preventDefault()
event.returnValue
event.stopPropagation()
For IE9 and FF you can just use preventDefault & stopPropagation.
To support IE8 and lower replace stopPropagation with cancelBubble and replace preventDefault with returnValue
Terminology
From quirksmode.org:
Event capturing
When you use event capturing
| |
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------
the event handler of element1 fires first, the event handler of element2 fires last.
Event bubbling
When you use event bubbling
/ \
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------
the event handler of element2 fires first, the event handler of element1 fires last.
Any event taking place in the W3C event model is first captured until it reaches the target element and then bubbles up again.
| | / \
-----------------| |--| |-----------------
| element1 | | | | |
| -------------| |--| |----------- |
| |element2 \ / | | | |
| -------------------------------- |
| W3C event model |
------------------------------------------
Interface
From w3.org, for event capture:
If the capturing EventListener wishes to prevent further processing of
the event from occurring it may call the stopPropagation method of the
Event interface. This will prevent further dispatch of the event,
although additional EventListeners registered at the same hierarchy
level will still receive the event. Once an event's stopPropagation
method has been called, further calls to that method have no
additional effect. If no additional capturers exist and
stopPropagation has not been called, the event triggers the
appropriate EventListeners on the target itself.
For event bubbling:
Any event handler may choose to prevent further event propagation by
calling the stopPropagation method of the Event interface. If any
EventListener calls this method, all additional EventListeners on the
current EventTarget will be triggered but bubbling will cease at that
level. Only one call to stopPropagation is required to prevent further
bubbling.
For event cancelation:
Cancelation is accomplished by calling the Event's preventDefault
method. If one or more EventListeners call preventDefault during
any phase of event flow the default action will be canceled.
Examples
In the following examples, a click on the hyperlink in the web browser triggers the event's flow (the event listeners are executed) and the event target's default action (a new tab is opened).
HTML:
<div id="a">
<a id="b" href="http://www.google.com/" target="_blank">Google</a>
</div>
<p id="c"></p>
JavaScript:
var el = document.getElementById("c");
function capturingOnClick1(ev) {
el.innerHTML += "DIV event capture<br>";
}
function capturingOnClick2(ev) {
el.innerHTML += "A event capture<br>";
}
function bubblingOnClick1(ev) {
el.innerHTML += "DIV event bubbling<br>";
}
function bubblingOnClick2(ev) {
el.innerHTML += "A event bubbling<br>";
}
// The 3rd parameter useCapture makes the event listener capturing (false by default)
document.getElementById("a").addEventListener("click", capturingOnClick1, true);
document.getElementById("b").addEventListener("click", capturingOnClick2, true);
document.getElementById("a").addEventListener("click", bubblingOnClick1, false);
document.getElementById("b").addEventListener("click", bubblingOnClick2, false);
Example 1: it results in the output
DIV event capture
A event capture
A event bubbling
DIV event bubbling
Example 2: adding stopPropagation() to the function
function capturingOnClick1(ev) {
el.innerHTML += "DIV event capture<br>";
ev.stopPropagation();
}
results in the output
DIV event capture
The event listener prevented further downward and upward propagation of the event. However it did not prevent the default action (a new tab opening).
Example 3: adding stopPropagation() to the function
function capturingOnClick2(ev) {
el.innerHTML += "A event capture<br>";
ev.stopPropagation();
}
or the function
function bubblingOnClick2(ev) {
el.innerHTML += "A event bubbling<br>";
ev.stopPropagation();
}
results in the output
DIV event capture
A event capture
A event bubbling
This is because both event listeners are registered on the same event target. The event listeners prevented further upward propagation of the event. However they did not prevent the default action (a new tab opening).
Example 4: adding preventDefault() to any function, for instance
function capturingOnClick1(ev) {
el.innerHTML += "DIV event capture<br>";
ev.preventDefault();
}
prevents a new tab from opening.
return false;
return false; does 3 separate things when you call it:
event.preventDefault() – It stops the browsers default behaviour.
event.stopPropagation() – It prevents the event from propagating (or “bubbling up”) the DOM.
Stops callback execution and returns immediately when called.
Note that this behaviour differs from normal (non-jQuery) event handlers, in which, notably, return false does not stop the event from bubbling up.
preventDefault();
preventDefault(); does one thing: It stops the browsers default behaviour.
When to use them?
We know what they do but when to use them? Simply it depends on what you want to accomplish. Use preventDefault(); if you want to “just” prevent the default browser behaviour. Use return false; when you want to prevent the default browser behaviour and prevent the event from propagating the DOM. In most situations where you would use return false; what you really want is preventDefault().
Examples:
Let’s try to understand with examples:
We will see pure JAVASCRIPT example
Example 1:
<div onclick='executeParent()'>
<a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
alert('Link Clicked');
}
function executeParent() {
alert('div Clicked');
}
</script>
Run the above code you will see the hyperlink ‘Click here to visit
stackoverflow.com‘ now if you click on that link first you will get
the javascript alert Link Clicked Next you will get the javascript
alert div Clicked and immediately you will be redirected to
stackoverflow.com.
Example 2:
<div onclick='executeParent()'>
<a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
event.preventDefault();
event.currentTarget.innerHTML = 'Click event prevented'
alert('Link Clicked');
}
function executeParent() {
alert('div Clicked');
}
</script>
Run the above code you will see the hyperlink ‘Click here to visit
stackoverflow.com‘ now if you click on that link first you will get
the javascript alert Link Clicked Next you will get the javascript
alert div Clicked Next you will see the hyperlink ‘Click here to
visit stackoverflow.com‘ replaced by the text ‘Click event prevented‘
and you will not be redirected to stackoverflow.com. This is due > to event.preventDefault() method we used to prevent the default click
action to be triggered.
Example 3:
<div onclick='executeParent()'>
<a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
event.stopPropagation();
event.currentTarget.innerHTML = 'Click event prevented'
alert('Link Clicked');
}
function executeParent() {
alert('div Clicked');
}
</script>
This time if you click on Link the function executeParent() will not
be called and you will not get the javascript alert div Clicked
this time. This is due to us having prevented the propagation to the
parent div using event.stopPropagation() method. Next you will see the
hyperlink ‘Click here to visit stackoverflow.com‘ replaced by the text
‘Click event is going to be executed‘ and immediately you will be
redirected to stackoverflow.com. This is because we haven’t prevented
the default click action from triggering this time using
event.preventDefault() method.
Example 4:
<div onclick='executeParent()'>
<a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
event.preventDefault();
event.stopPropagation();
event.currentTarget.innerHTML = 'Click event prevented'
alert('Link Clicked');
}
function executeParent() {
alert('Div Clicked');
}
</script>
If you click on the Link, the function executeParent() will not be
called and you will not get the javascript alert. This is due to us
having prevented the propagation to the parent div using
event.stopPropagation() method. Next you will see the hyperlink ‘Click
here to visit stackoverflow.com‘ replaced by the text ‘Click event
prevented‘ and you will not be redirected to stackoverflow.com. This
is because we have prevented the default click action from triggering
this time using event.preventDefault() method.
Example 5:
For return false I have three examples and all appear to be doing the exact same thing (just returning false), but in reality the
results are quite different. Here's what actually happens in each of
the above.
cases:
Returning false from an inline event handler prevents the browser from navigating to the link address, but it doesn't stop the event from propagating through the DOM.
Returning false from a jQuery event handler prevents the browser from navigating to the link address and it stops the event from propagating through the DOM.
Returning false from a regular DOM event handler does absolutely nothing.
Will see all three example.
Inline return false.
<div onclick='executeParent()'>
<a href='https://stackoverflow.com' onclick='return false'>Click here to visit stackoverflow.com</a>
</div>
<script>
var link = document.querySelector('a');
link.addEventListener('click', function() {
event.currentTarget.innerHTML = 'Click event prevented using inline html'
alert('Link Clicked');
});
function executeParent() {
alert('Div Clicked');
}
</script>
Returning false from a jQuery event handler.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<a href='https://stackoverflow.com'>Click here to visit stackoverflow.com</a>
</div>
<script>
$('a').click(function(event) {
alert('Link Clicked');
$('a').text('Click event prevented using return FALSE');
$('a').contents().unwrap();
return false;
});
$('div').click(function(event) {
alert('Div clicked');
});
</script>
Returning false from a regular DOM event handler.
<div onclick='executeParent()'>
<a href='https://stackoverflow.com' onclick='executeChild()'>Click here to visit stackoverflow.com</a>
</div>
<script>
function executeChild() {
event.currentTarget.innerHTML = 'Click event prevented'
alert('Link Clicked');
return false
}
function executeParent() {
alert('Div Clicked');
}
</script>
Hope these examples are clear. Try executing all these examples in a html file to see how they work.
This is the quote from here
Event.preventDefault
The preventDefault method prevents an event from carrying out its default functionality. For example, you would use preventDefault on an A element to stop clicking that element from leaving the current page:
//clicking the link will *not* allow the user to leave the page
myChildElement.onclick = function(e) {
e.preventDefault();
console.log('brick me!');
};
//clicking the parent node will run the following console statement because event propagation occurs
logo.parentNode.onclick = function(e) {
console.log('you bricked my child!');
};
While the element's default functionality is bricked, the event continues to bubble up the DOM.
Event.stopPropagation
The second method, stopPropagation, allows the event's default functionality to happen but prevents the event from propagating:
//clicking the element will allow the default action to occur but propagation will be stopped...
myChildElement.onclick = function(e) {
e.stopPropagation();
console.log('prop stop! no bubbles!');
};
//since propagation was stopped by the child element's onClick, this message will never be seen!
myChildElement.parentNode.onclick = function(e) {
console.log('you will never see this message!');
};
stopPropagation effectively stops parent elements from knowing about a given event on its child.
While a simple stop method allows us to quickly handle events, it's
important to think about what exactly you want to happen with
bubbling. I'd bet that all a developer really wants is preventDefault
90% of the time! Incorrectly "stopping" an event could cause you
numerous troubles down the line; your plugins may not work and your
third party plugins could be bricked. Or worse yet -- your code
breaks other functionality on a site.
event.preventDefault()
Prevents the browsers default behaviour (such as opening a link), but does not stop the event from bubbling up the DOM.
event.stopPropagation()Prevents the event from bubbling up the DOM, but does not stop the browsers default behaviour.
return false;Usually seen in jQuery code, it Prevents the browsers default behaviour, Prevents the event from bubbling up the
DOM, and immediately Returns from any callback.
Check out this really nice & easy 4 min read with examples from where the above piece was taken.
event.preventDefault(); Stops the default action of an element from happening.
event.stopPropagation(); Prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.
For example, if there is a link with a click method attached inside of a DIV or FORM that also has a click method attached, it will prevent the DIV or FORM click method from firing.
Event.preventDefault- stops browser default behaviour. Now comes what is browser default behaviour. Assume you have a anchor tag and it has got a href attribute and this anchor tag is nested inside a div tag which has got a click event. Default behaviour of anchor tag is when clicked on the anchor tag it should navigate, but what event.preventDefault does is it stops the navigation in this case. But it never stops the bubbling of event or escalation of event i.e
<div class="container">
Click Me!
</div>
$('.container').on('click', function(e) {
console.log('container was clicked');
});
$('.element').on('click', function(e) {
e.preventDefault(); // Now link won't go anywhere
console.log('element was clicked');
});
The result will be
"element was clicked"
"container was clicked"
Now event.StopPropation it stops bubbling of event or escalation of event. Now with above example
$('.container').on('click', function(e) {
console.log('container was clicked');
});
$('.element').on('click', function(e) {
e.preventDefault(); // Now link won't go anywhere
e.stopPropagation(); // Now the event won't bubble up
console.log('element was clicked');
});
Result will be
"element was clicked"
For more info refer this link
https://codeplanet.io/preventdefault-vs-stoppropagation-vs-stopimmediatepropagation/
$("#but").click(function(event){
console.log("hello");
event.preventDefault();
});
$("#foo").click(function(){
alert("parent click event fired !");
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="foo">
<button id="but">button</button>
</div>
What is the difference between event bubbling and capturing? When should one use bubbling vs capturing?
Event bubbling and capturing are two ways of event propagation in the HTML DOM API, when an event occurs in an element inside another element, and both elements have registered a handle for that event. The event propagation mode determines in which order the elements receive the event.
With bubbling, the event is first captured and handled by the innermost element and then propagated to outer elements.
With capturing, the event is first captured by the outermost element and propagated to the inner elements.
Capturing is also called "trickling", which helps remember the propagation order:
trickle down, bubble up
Back in the old days, Netscape advocated event capturing, while Microsoft promoted event bubbling. Both are part of the W3C Document Object Model Events standard (2000).
IE < 9 uses only event bubbling, whereas IE9+ and all major browsers support both. On the other hand, the performance of event bubbling may be slightly lower for complex DOMs.
We can use the addEventListener(type, listener, useCapture) to register event handlers for in either bubbling (default) or capturing mode. To use the capturing model pass the third argument as true.
Example
<div>
<ul>
<li></li>
</ul>
</div>
In the structure above, assume that a click event occurred in the li element.
In capturing model, the event will be handled by the div first (click event handlers in the div will fire first), then in the ul, then at the last in the target element, li.
In the bubbling model, the opposite will happen: the event will be first handled by the li, then by the ul, and at last by the div element.
For more information, see
Event Order on QuirksMode
addEventListener on MDN
Events Advanced on QuirksMode
In the example below, if you click on any of the highlighted elements, you can see that the capturing phase of the event propagation flow occurs first, followed by the bubbling phase.
var logElement = document.getElementById('log');
function log(msg) {
logElement.innerHTML += ('<p>' + msg + '</p>');
}
function capture() {
log('capture: ' + this.firstChild.nodeValue.trim());
}
function bubble() {
log('bubble: ' + this.firstChild.nodeValue.trim());
}
function clearOutput() {
logElement.innerHTML = "";
}
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', capture, true);
divs[i].addEventListener('click', bubble, false);
}
var clearButton = document.getElementById('clear');
clearButton.addEventListener('click', clearOutput);
p {
line-height: 0;
}
div {
display:inline-block;
padding: 5px;
background: #fff;
border: 1px solid #aaa;
cursor: pointer;
}
div:hover {
border: 1px solid #faa;
background: #fdd;
}
<div>1
<div>2
<div>3
<div>4
<div>5</div>
</div>
</div>
</div>
</div>
<button id="clear">clear output</button>
<section id="log"></section>
Another example at JSFiddle.
Description:
quirksmode.org has a nice description of this. In a nutshell (copied from quirksmode):
Event capturing
When you use event capturing
| |
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------
the event handler of element1 fires first, the event handler of element2 fires last.
Event bubbling
When you use event bubbling
/ \
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------
the event handler of element2 fires first, the event handler of element1 fires last.
What to use?
It depends on what you want to do. There is no better. The difference is the order of the execution of the event handlers. Most of the time it will be fine to fire event handlers in the bubbling phase but it can also be necessary to fire them earlier.
If there are two elements element 1 and element 2. Element 2 is inside element 1 and we attach an event handler with both the elements lets say onClick. Now when we click on element 2 then eventHandler for both the elements will be executed. Now here the question is in which order the event will execute. If the event attached with element 1 executes first it is called event capturing and if the event attached with element 2 executes first this is called event bubbling.
As per W3C the event will start in the capturing phase until it reaches the target comes back to the element and then it starts bubbling
The capturing and bubbling states are known by the useCapture parameter of addEventListener method
eventTarget.addEventListener(type,listener,[,useCapture]);
By Default useCapture is false. It means it is in the bubbling phase.
var div1 = document.querySelector("#div1");
var div2 = document.querySelector("#div2");
div1.addEventListener("click", function (event) {
alert("you clicked on div 1");
}, true);
div2.addEventListener("click", function (event) {
alert("you clicked on div 2");
}, false);
#div1{
background-color:red;
padding: 24px;
}
#div2{
background-color:green;
}
<div id="div1">
div 1
<div id="div2">
div 2
</div>
</div>
Please try with changing true and false.
I have found this tutorial at javascript.info to be very clear in explaining this topic. And its 3-points summary at the end is really talking to the crucial points. I quote it here:
Events first are captured down to deepest target, then bubble up. In
IE<9 they only bubble.
All handlers work on bubbling stage excepts
addEventListener with last argument true, which is the only way to
catch the event on capturing stage.
Bubbling/capturing can be
stopped by event.cancelBubble=true (IE) or event.stopPropagation()
for other browsers.
There's also the Event.eventPhase property which can tell you if the event is at target or comes from somewhere else, and it is fully supported by browsers.
Expanding on the already great snippet from the accepted answer, this is the output using the eventPhase property
var logElement = document.getElementById('log');
function log(msg) {
if (logElement.innerHTML == "<p>No logs</p>")
logElement.innerHTML = "";
logElement.innerHTML += ('<p>' + msg + '</p>');
}
function humanizeEvent(eventPhase){
switch(eventPhase){
case 1: //Event.CAPTURING_PHASE
return "Event is being propagated through the target's ancestor objects";
case 2: //Event.AT_TARGET
return "The event has arrived at the event's target";
case 3: //Event.BUBBLING_PHASE
return "The event is propagating back up through the target's ancestors in reverse order";
}
}
function capture(e) {
log('capture: ' + this.firstChild.nodeValue.trim() + "; " +
humanizeEvent(e.eventPhase));
}
function bubble(e) {
log('bubble: ' + this.firstChild.nodeValue.trim() + "; " +
humanizeEvent(e.eventPhase));
}
var divs = document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
divs[i].addEventListener('click', capture, true);
divs[i].addEventListener('click', bubble, false);
}
p {
line-height: 0;
}
div {
display:inline-block;
padding: 5px;
background: #fff;
border: 1px solid #aaa;
cursor: pointer;
}
div:hover {
border: 1px solid #faa;
background: #fdd;
}
<div>1
<div>2
<div>3
<div>4
<div>5</div>
</div>
</div>
</div>
</div>
<button onclick="document.getElementById('log').innerHTML = '<p>No logs</p>';">Clear logs</button>
<section id="log"></section>
DOM Events describes 3 phases of event propagation: Capturing phase – the event goes down to the element. Target phase – the event reached the target element. Bubbling phase – the event bubbles up from the element.
Bubbling
Event propagate to the upto root element is **BUBBLING**.
Capturing
Event propagate from body(root) element to eventTriggered Element is **CAPTURING**.
As other said, bubbling and capturing describe in which order some nested elements receive a given event.
I wanted to point out that for the innermost element may appear something strange. Indeed, in this case the order in which the event listeners are added does matter.
In the following example, capturing for div2 will be executed first than bubbling; while bubbling for div4 will be executed first than capturing.
function addClickListener (msg, num, type) {
document.querySelector("#div" + num)
.addEventListener("click", () => alert(msg + num), type);
}
bubble = (num) => addClickListener("bubble ", num, false);
capture = (num) => addClickListener("capture ", num, true);
// first capture then bubble
capture(1);
capture(2);
bubble(2);
bubble(1);
// try reverse order
bubble(3);
bubble(4);
capture(4);
capture(3);
#div1, #div2, #div3, #div4 {
border: solid 1px;
padding: 3px;
margin: 3px;
}
<div id="div1">
div 1
<div id="div2">
div 2
</div>
</div>
<div id="div3">
div 3
<div id="div4">
div 4
</div>
</div>
EDIT: Such behavior may vary according to the browser (e.g. currently occurs on Firefox, but not on Chrome and Edge). Nevertheless, I think one should be aware of it.
When browser detects an event, it tries to find an event handler. This process has 3 phases. Let's say we have these elements
<body>
<div>
<button>click</button>
</div>
</body>
1-Capture Phase
browser is going to take a look at the element that was just clicked. Then it will go to the top parent element which is body. if there is any click handle in body, the browser will call it. after checking the body element, it will look at the second top parent element which is div element. This process will repeat until the browser gets down to the button element at the very bottom. Once it sees the button element, Phase One- Capturing will be over. Most of the time we ignore this phase. This code ignores this phase
document.addEventListener('click',handleClick)
If you want to involve this phase, you have to write this
document.addEventListener('click',handleClick,true)
We need this phase when we need to detect a click outside the target. maybe we have a dropdown or a modal open and we want to close it if the user clicks on anywhere outside the modal or dropdown
2-Target Phase
the browser will look at the clicked element which is the Button and if the button has an event handler, it will call it.
3- Bubble Phase
Opposite to Capture Phase, in this phase, browser will start the process from the immediate parent element which is div element in this case and then it will visit the body element. This code will set up the event handler for the bubble phase
document.addEventListener('click',handleClick,false)
Right now, I have an event listener that listens to a click on the screen. There is also a button on the screen. When I click on the button the event listener will execute before the onclick. Is there a way I can make onclick have higher priority?
<script>
document.body.addEventListener('click',function(){alert('1');}, false);
function clicked() {
alert('2');
}
</script>
<button onclick="clicked()">Click this</button>
Clicking the button also triggers the event handler. 1 shows before 2, when I click the button. I want 2 to show first.
addEventListner's third argument is the useCapture flag. If you set it to true, handler will be executed while the event is traveling down to the button element. However, if you set it to false, the handler will be triggered while the event is bubbling up:
capture phase | | / \ bubbling up
-----------------| |--| |-----------------
| element1 | | | | |
| -------------| |--| |----------- |
| |element2 \ / | | | |
| -------------------------------- |
| W3C event model |
------------------------------------------
From: http://www.quirksmode.org/js/events_order.html#link4
In your example, the onclick should be executed before the click handler on the body tag. If you want to reverse the order of execution, you should capture the event at body.
One solution would be to use inline differently. When .addEventListener need to wait for DOM, on the other hand inline onclick binds while DOM is loading.
<script>
document.body.addEventListener('click',function(){alert('1');}, false);
function clicked() {
alert('2');
}
</script>
<button onclick="alert('2');">Click this</button>
JSFIDDLE: http://jsfiddle.net/8j9q23jw/
I want to understand how exactly to interpret bubbling. Does it mean going up the HTML code hierarchy or something else?
Secondly, I was going through an example and I could not understand the last part where it says
The P-based click handler listens for the click event and then prevents it from being propagated (bubbling up)
What does this mean?
The concept of "bubbling up" is like if you have a child element with a click event and you don't want it to trigger the click event of the parent. You could use event.stopPropagation().
event.stopPropagation() basically says only apply this click event to THIS CHILD NODE and don't tell the parent containers anything because I don't want them to react.
Event Capturing:
| |
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 \ / | |
| ------------------------- |
| Event CAPTURING |
-----------------------------------
Event Bubbling:
/ \
---------------| |-----------------
| element1 | | |
| -----------| |----------- |
| |element2 | | | |
| ------------------------- |
| Event BUBBLING |
-----------------------------------
If you are using live() or delegate() you will need to return false;, though it may not work. Read the quote below.
Per jQuery docs:
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 propagate
to the elements to which they are delegated; event handlers bound on
any elements below it in the DOM tree will already have been executed
by the time the delegated event handler is called. These handlers,
therefore, may prevent the delegated handler from triggering by
calling event.stopPropagation() or returning false.
In the past it was a platform issue, Internet Explorer had a bubbling model, and Netscape was more about capturing (yet supported both).
The W3C model calls for you be able to choose which one you want.
I think bubbling is more popular because, as stated there are some platforms that only support bubbling...and it sort of makes sense as a "default" mode.
Which one you choose is largely a product of what you are doing and what makes sense to you.
More info http://www.quirksmode.org/js/events_order.html
Another great resource: http://fuelyourcoding.com/jquery-events-stop-misusing-return-false/
return false;
will prevent "bubbling". It's used to stop default actions like checking a checkbox, opening a select, a click, etc.
To stop further handlers from executing after one bound using .live(),
the handler must return false. Calling .stopPropagation() will not
accomplish this.
From Caveats in jQuery .live()
Reasoning (thanks to #AlienWebguy):
The reason stopPropagation() doesn't work with live() is that live() binds the event to document so by the time it fires there's no where else for it to propagate.
What it says is that the live () method attach a handler to the document element and check the target of the event to see where it comes from. If the target match the selector, then it fires the eventHandler. All that repose on the bubbling event system.
In the example, the click handler on the p element, witch is an ancestor of the a element, cancel the bubbling by returning false. Then the document element will never receive the event, so it will not trigger the event handler.
In the below example it is attaching a click event to anchor with id "anchor". This anchor is within a div which also has a click event attached. If we click on this anchor it is as good as we are clicking on the containing div. Now if we want to do some stuff on this anchor click but do not want the div's click to be fired we can stop the event bubling as below.
<div id="div">
</div>
$("#div").click(function(e){//On anchor click this event will not be fired as we have stop the event propagation in anchor click handler.
//Do stuff here
});
$("#anchor").click(function(e){
//Do stuff here
//This line stops the event bubling and
//jquery has abstracted it in the event object to make it cross browser compatible.
e.stopPropagation();
});
Also:
event.stopPropagation()
http://api.jquery.com/event.stopPropagation/
Yes, the event goes up the tree and if any element has a handler for that event it will be called.
By adding return:false in a handler of one of the elements the event will be prevented from bubbling.
These two links provide clear and elaborate explanation on event bubbling (as well as commonly used event concepts).
http://jqfundamentals.com/chapter/events
http://www.mattlunn.me.uk/blog/2012/05/what-does-event-bubbling-mean/
From the first link
event will be triggered for the a element as well as for all of
the elements that contain the a — all the way up to the document
From the second link
<div>
<h1>
<a href="#">
<span>Hello</span>
</a>
</h1>
</div>
Lets assume we click the span, which causes a click event to be fired on the span; nothing revolutionary so far. However, the event then propagates (or bubbles) to the parent of the span (the ), and a click event is fired on that. This process repeats for the next parent (or ancestor) up to the document element.
Now let's put all this into the context of a DOM. The DOM is a... tree and each element is a node in the DOM tree. Bubbling is then merely the traversal of a node, some element to the root node, document (follow your parent until you can't anymore)
Is there any difference between calling event.stopImmediatePropagation() and return false inside an event handler ?
Yes they are different.
return false is basically the same as calling both, event.stopPropagation() and event.preventDefault().
Whereas event.stopImmediatePropagation() is the same as event.stopPropagation() plus preventing other registered event handlers on the same element to be executed. So it does not prevent the default action for an event, such as following a clicked link.
In short:
stop | prevent | prevent "same element"
bubbling | default action | event handlers
return false Yes Yes No
preventDefault No Yes No
stopPropagation Yes No No
stopImmediatePropagation Yes No Yes
return false also works in "normal" JavaScript event handlers
event.stopPropagation() and event.preventDefault() also work in "normal" JavaScript event handlers (in a W3C compatible browser), whereas event.stopImmediatePropagation() is an extension from jQuery (update: apparently it is part of the DOM Level 3 Events specification).
Note: return false does not prevent the event from bubbling up in "normal" (non-jQuery) event handlers (see this answer)(but still prevents the default action).
Maybe worth reading:
jQuery Events: Stop (Mis)Using Return False
quirksmode.org - Event order
Returning false will stop event bubbling, but other bound events will fire. However stopImmediatePropagation prevents other bound events from firing and stops bubbling.
Code Example of this on jsfiddle.
Here is the complete demo for return false, preventDefault, stopPropagation and stopImmediatePropagation:
var kid = document.getElementsByTagName('button')[0];
var dad = document.getElementsByTagName('div')[0];
kid.addEventListener('click', function(e) {
console.log('kid here');
e.stopImmediatePropagation();
});
kid.addEventListener('click', function(e) {
console.log('neighbour kid here');
});
dad.addEventListener('click', function(e) {
console.log('dad here');
});
dad.addEventListener('click', function(e) {
console.log('neighbour dad here');
});
<div>
<button>press</button>
</div>
(Also available on JSFiddle.)
The table in manwal’s answer is not fully correct.
stop | prevent | prevent
bubbling | default action | event handlers
| | Same Element | Parent Element
return false Yes Yes No No
preventDefault No Yes No No
stopPropagation Yes No No Yes
stopImmediatePropagation Yes No Yes **Yes**
Yes. event.stopImmediatePropagation() won't let any other handlers for that event be called, regardless of where they are bound. Return false only stops handlers bound to other elements (ie not the same element as the event handler dealing with the stopImmediatePropagation() call) from receiving the event.
#FelixKling answer's table having great concept:
I am posting more explained table:
stop | prevent | prevent |
bubbling | default action | event handlers |
Same Element | Parent Element
return false Yes Yes No No
preventDefault No Yes No No
stopPropagation Yes No No Yes
stopImmediatePropagation Yes No Yes No
Reference: https://stackoverflow.com/a/5302939/2236219