issue with event Bubbling in js - javascript

<!DOCTYPE HTML>
<html>
<body>
<style type="text/css">
#a {background-color:blue;width:100px;height:200px;}
#b {background-color:red;margin-left:25px;width:50px;height:100px;}
</style>
<div id="a">a
<div id="b">b</div>
</div>
<script>
document.getElementById("a").onclick = function() {console.log("A is clicked");}
document.getElementById("b").onclick = function(event) {console.log("B is clicked");event.stopPropagation();}
document.onclick = function() {console.log("Document is clicked");}
</script>
</body>
</html>
Questions:
1.function(event), event is formal parameter, what is the actual parameter? how did actual parameter pass to event? Because usually we use parameters in below style:
function method(int num){ //num is the formal
/*implementation*/
}
//in main
method(42); //42 is the actual
when I clicked div a, in console, it shows:
A is clicked
Document is clicked
I thought the result should be
A is clicked
B is clicked
this is my thought: when clicked div a, document.getElementById("a").onclick got excuted, then document.getElementById("b").onclick got excuted, since we have event.stopPropagation(); it will stop in div b, and will not excute document.onclick, but it seems not work this way, can anyone help me to understand what happened here?

function(event), event is formal parameter, what is the actual parameter?
The actual parameter is an event object, created by the browser. For a click event, it will be an instance of MouseEvent.
when I clicked div a... I thought the result should be...
You clicked on the parent of b. The event propagates up the DOM tree from the target, so it will never touch b. The propagation phase will start at a, and move up through each parent until it reaches the document.
Had you clicked on b, the stopPropagation method would have prevented the event from bubbling and you would only see "B is clicked" in the output.

Event propagation means bubling up of event in to the ancestor chain till the document object.
So in your case both event attached to element a and document are fired. When you click on element b then event attached to only element b is fired since the propagation is prevented from that point onward.

The event is the browser event. You cannot really change it, but you can use closures or use data attributes to pass more data into your event handler.
You got the right result on clicking A. The event bubbles upwards to until it reaches the document's root element. If you stop propagation, you prevent it from bubbling upwards to it's parent elements.
If you click b then it would bubble upwards to a then to the body. But you stop propagation on b so the only output should be
B is clicked
The event object itself is different in every browser, although there is a recommendation for it. Some browsers don't support the stopPropagation and preventDefault methods or other properties (for example older IEs don't fully support the DOM Level 2 specs).

Related

querySelector bug <a> [duplicate]

Can anyone please tell me the exact difference between currentTarget and target property in JavaScript events with example and which property is used in which scenario?
Events bubble by default. So the difference between the two is:
target is the element that triggered the event (e.g., the user clicked on)
currentTarget is the element that the event listener is attached to.
target = element that triggered event.
currentTarget = element that has the event listener.
Minimal runnable example
window.onload = function() {
var resultElem = document.getElementById('result')
document.getElementById('1').addEventListener(
'click',
function(event) {
resultElem.innerHTML += ('<div>target: ' + event.target.id + '</div>')
resultElem.innerHTML += ('<div>currentTarget: ' + event.currentTarget.id + '</div>')
},
false
)
document.getElementById('2').dispatchEvent(
new Event('click', { bubbles:true }))
}
<div id="1">1 click me
<div id="2">2 click me as well</div>
</div>
<div id="result">
<div>result:</div>
</div>
If you click on:
2 click me as well
then 1 listens to it, and appends to the result:
target: 2
currentTarget: 1
because in that case:
2 is the element that originated the event
1 is the element that listened to the event
If you click on:
1 click me
instead, the result is:
target: 1
currentTarget: 1
Tested on Chromium 71.
For events whose bubbles property is true, they bubble.
Most events do bubble, except several, namely focus, blur, mouseenter, mouseleave, ...
If an event evt bubbles, the evt.currentTarget is changed to the current target in its bubbling path, while the evt.target keeps the same value as the original target which triggered the event.
It is worth noting that if your event handler (of an event that bubbles) is asynchronous and the handler uses evt.currentTarget. currentTarget should be cached locally because the event object is reused in the bubbling chain (codepen).
const clickHandler = evt => {
const {currentTarget} = evt // cache property locally
setTimeout(() => {
console.log('evt.currentTarget changed', evt.currentTarget !== currentTarget)
}, 3000)
}
If you use React, from v17, react drops the Event Pooling.
Therefore, the event object is refreshed in the handler and can be safe to use in asynchronous calls (codepen).
↑is not always true. onClick event's currentTarget is undefined after the event handler finishes. In conclusion, always cache the event's properties locally if you are going to use them after a synchronous call.
From react docs
Note:
As of v17, e.persist() doesn’t do anything because the SyntheticEvent
is no longer pooled.
And many other things that are too long to be pasted in an answer, so I summarized and made a blog post here.
If this isn't sticking, try this:
current in currentTarget refers to the present. It's the most recent target that caught the event that bubbled up from elsewhere.
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
If click on the P tag in above code then you will get three alert,and if you click on the div tag you will get two alert and a single alert on clicking the form tag.
And now see the following code,
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<script>
function fun(event){
alert(event.target+" "+event.currentTarget);
}
</script>
<form>FORM
<div onclick="fun(event)">DIV
<p>P</p>
</div>
</form>
We just removed onclick from the P and form tag and now when we click we on P tag we get only one alert:
[object HTMLParagraphElement] [object HTMLDivElement]
Here event.target is [object HTMLParagraphElement],and event.curentTarget is [object HTMLDivElement]:
So
event.target is the node from which the event originated,
and
event.currentTarget, on the opposite, refers to the node on which current-event listener was attached.To know more see bubbling
Here we clicked on P tag but we don't have listener on P but on its parent element div.
Event.currentTarget is the element to which the event handler has been
attached, as opposed to Event.target, which identifies the element on
which the event occurred and which may be its descendant.
Source: MDN
target always refers to the element in front of addEventListener - it's the element on which the event originated.
currentTarget tells you - if this is an event that's bubbling - the element that currently has the event listener attached (which will fire the event handler if the event occurs).
See this CodePen for an example. If you open up developer tools and click the square, you'll see that first the div is the target and the currentTarget, but the event bubbles up to the main element - then main element becomes the currentTarget, while the div is still the target. Note the event listener needs to be attached to both elements for the bubbling to occur.
event.target is the node from which the event originated, ie. wherever you place your event listener (on paragraph or span), event.target refers to node (where user clicked).
event.currentTarget, on the opposite, refers to the node on which current-event listener was attached. Ie. if we attached our event listener on paragraph node, then event.currentTarget refers to paragraph while event.target still refers to span.
Note: that if we also have an event listener on body, then for this event-listener, event.currentTarget refers to body (ie. event provided as input to event-listerners is updated each time event is bubbling one node up).
Here's a simple scenario to explain why it's needed. Let's say there are some messages that you show to the user with the format below, but you also want to give them the freedom to close them (unless you have a special mental disorder), so here are some message panes:
[ A message will be in this pane [x] ]
[ A message will be in this pane [x] ]
[ A message will be in this pane [x] ]
and when the user clicks on the [x] button on each, the whole corresponding pane must be removed.
Here's the HTML code for the pane:
<div class="pane">
A message will be here
<span class="remove-button">[x]</span>
</div>
Now where do you want to add the click event listener? The user clicks on [x], but you want to remove the pane, so:
If you add the click event listener to the [x], then you will have to find its parent on DOM and remove it... which is possible but ugly and "DOM dependent".
And if you add the click event listener to the pane, clicking "everywhere on the pane" will remove it, and not just clicking on its [x] button.
So what can we do? We can use the "Bubbles Up" feature of the event system:
"Events are raised and bubble up the DOM tree regardless of the existence of any event handlers."
In our example, this means that even if we add the event handlers to the panes, we will be able to catch the events raised specifically by the [x] button clicks (because events bubble up). So there can be difference between where an event is raised, and where we catch and handle it.
Where it's raised will be in the event.target, and where it's caught will be in the event.currentTarget (where we're currently handling it). So:
let panes = document.getElementsByClassName("pane");
for(let pane of panes){
pane.addEventListener('click', hndlr);
}
function hndlr(e){
if(e.target.classList.contains('remove-button')){
e.currentTarget.remove();
}
}
(The credit of this example goes to the website JavaScript.info)
An experiment:
document.addEventListener("click", (e) => {
console.log(e.target, e.currentTarget);
});
document.querySelector("p").click();
output:
<p></p>
#document
The target (<p></p>) seems to be the element clicked, while the currentTarget (#document) is the element that is listening for the click event.

Accessing data attribute of clicked element with javascript [duplicate]

Can anyone please tell me the exact difference between currentTarget and target property in JavaScript events with example and which property is used in which scenario?
Events bubble by default. So the difference between the two is:
target is the element that triggered the event (e.g., the user clicked on)
currentTarget is the element that the event listener is attached to.
target = element that triggered event.
currentTarget = element that has the event listener.
Minimal runnable example
window.onload = function() {
var resultElem = document.getElementById('result')
document.getElementById('1').addEventListener(
'click',
function(event) {
resultElem.innerHTML += ('<div>target: ' + event.target.id + '</div>')
resultElem.innerHTML += ('<div>currentTarget: ' + event.currentTarget.id + '</div>')
},
false
)
document.getElementById('2').dispatchEvent(
new Event('click', { bubbles:true }))
}
<div id="1">1 click me
<div id="2">2 click me as well</div>
</div>
<div id="result">
<div>result:</div>
</div>
If you click on:
2 click me as well
then 1 listens to it, and appends to the result:
target: 2
currentTarget: 1
because in that case:
2 is the element that originated the event
1 is the element that listened to the event
If you click on:
1 click me
instead, the result is:
target: 1
currentTarget: 1
Tested on Chromium 71.
For events whose bubbles property is true, they bubble.
Most events do bubble, except several, namely focus, blur, mouseenter, mouseleave, ...
If an event evt bubbles, the evt.currentTarget is changed to the current target in its bubbling path, while the evt.target keeps the same value as the original target which triggered the event.
It is worth noting that if your event handler (of an event that bubbles) is asynchronous and the handler uses evt.currentTarget. currentTarget should be cached locally because the event object is reused in the bubbling chain (codepen).
const clickHandler = evt => {
const {currentTarget} = evt // cache property locally
setTimeout(() => {
console.log('evt.currentTarget changed', evt.currentTarget !== currentTarget)
}, 3000)
}
If you use React, from v17, react drops the Event Pooling.
Therefore, the event object is refreshed in the handler and can be safe to use in asynchronous calls (codepen).
↑is not always true. onClick event's currentTarget is undefined after the event handler finishes. In conclusion, always cache the event's properties locally if you are going to use them after a synchronous call.
From react docs
Note:
As of v17, e.persist() doesn’t do anything because the SyntheticEvent
is no longer pooled.
And many other things that are too long to be pasted in an answer, so I summarized and made a blog post here.
If this isn't sticking, try this:
current in currentTarget refers to the present. It's the most recent target that caught the event that bubbled up from elsewhere.
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
If click on the P tag in above code then you will get three alert,and if you click on the div tag you will get two alert and a single alert on clicking the form tag.
And now see the following code,
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<script>
function fun(event){
alert(event.target+" "+event.currentTarget);
}
</script>
<form>FORM
<div onclick="fun(event)">DIV
<p>P</p>
</div>
</form>
We just removed onclick from the P and form tag and now when we click we on P tag we get only one alert:
[object HTMLParagraphElement] [object HTMLDivElement]
Here event.target is [object HTMLParagraphElement],and event.curentTarget is [object HTMLDivElement]:
So
event.target is the node from which the event originated,
and
event.currentTarget, on the opposite, refers to the node on which current-event listener was attached.To know more see bubbling
Here we clicked on P tag but we don't have listener on P but on its parent element div.
Event.currentTarget is the element to which the event handler has been
attached, as opposed to Event.target, which identifies the element on
which the event occurred and which may be its descendant.
Source: MDN
target always refers to the element in front of addEventListener - it's the element on which the event originated.
currentTarget tells you - if this is an event that's bubbling - the element that currently has the event listener attached (which will fire the event handler if the event occurs).
See this CodePen for an example. If you open up developer tools and click the square, you'll see that first the div is the target and the currentTarget, but the event bubbles up to the main element - then main element becomes the currentTarget, while the div is still the target. Note the event listener needs to be attached to both elements for the bubbling to occur.
event.target is the node from which the event originated, ie. wherever you place your event listener (on paragraph or span), event.target refers to node (where user clicked).
event.currentTarget, on the opposite, refers to the node on which current-event listener was attached. Ie. if we attached our event listener on paragraph node, then event.currentTarget refers to paragraph while event.target still refers to span.
Note: that if we also have an event listener on body, then for this event-listener, event.currentTarget refers to body (ie. event provided as input to event-listerners is updated each time event is bubbling one node up).
Here's a simple scenario to explain why it's needed. Let's say there are some messages that you show to the user with the format below, but you also want to give them the freedom to close them (unless you have a special mental disorder), so here are some message panes:
[ A message will be in this pane [x] ]
[ A message will be in this pane [x] ]
[ A message will be in this pane [x] ]
and when the user clicks on the [x] button on each, the whole corresponding pane must be removed.
Here's the HTML code for the pane:
<div class="pane">
A message will be here
<span class="remove-button">[x]</span>
</div>
Now where do you want to add the click event listener? The user clicks on [x], but you want to remove the pane, so:
If you add the click event listener to the [x], then you will have to find its parent on DOM and remove it... which is possible but ugly and "DOM dependent".
And if you add the click event listener to the pane, clicking "everywhere on the pane" will remove it, and not just clicking on its [x] button.
So what can we do? We can use the "Bubbles Up" feature of the event system:
"Events are raised and bubble up the DOM tree regardless of the existence of any event handlers."
In our example, this means that even if we add the event handlers to the panes, we will be able to catch the events raised specifically by the [x] button clicks (because events bubble up). So there can be difference between where an event is raised, and where we catch and handle it.
Where it's raised will be in the event.target, and where it's caught will be in the event.currentTarget (where we're currently handling it). So:
let panes = document.getElementsByClassName("pane");
for(let pane of panes){
pane.addEventListener('click', hndlr);
}
function hndlr(e){
if(e.target.classList.contains('remove-button')){
e.currentTarget.remove();
}
}
(The credit of this example goes to the website JavaScript.info)
An experiment:
document.addEventListener("click", (e) => {
console.log(e.target, e.currentTarget);
});
document.querySelector("p").click();
output:
<p></p>
#document
The target (<p></p>) seems to be the element clicked, while the currentTarget (#document) is the element that is listening for the click event.

When using event.target.getAttribute() on <button> element, it returns null (seemingly) at random? [duplicate]

Can anyone please tell me the exact difference between currentTarget and target property in JavaScript events with example and which property is used in which scenario?
Events bubble by default. So the difference between the two is:
target is the element that triggered the event (e.g., the user clicked on)
currentTarget is the element that the event listener is attached to.
target = element that triggered event.
currentTarget = element that has the event listener.
Minimal runnable example
window.onload = function() {
var resultElem = document.getElementById('result')
document.getElementById('1').addEventListener(
'click',
function(event) {
resultElem.innerHTML += ('<div>target: ' + event.target.id + '</div>')
resultElem.innerHTML += ('<div>currentTarget: ' + event.currentTarget.id + '</div>')
},
false
)
document.getElementById('2').dispatchEvent(
new Event('click', { bubbles:true }))
}
<div id="1">1 click me
<div id="2">2 click me as well</div>
</div>
<div id="result">
<div>result:</div>
</div>
If you click on:
2 click me as well
then 1 listens to it, and appends to the result:
target: 2
currentTarget: 1
because in that case:
2 is the element that originated the event
1 is the element that listened to the event
If you click on:
1 click me
instead, the result is:
target: 1
currentTarget: 1
Tested on Chromium 71.
For events whose bubbles property is true, they bubble.
Most events do bubble, except several, namely focus, blur, mouseenter, mouseleave, ...
If an event evt bubbles, the evt.currentTarget is changed to the current target in its bubbling path, while the evt.target keeps the same value as the original target which triggered the event.
It is worth noting that if your event handler (of an event that bubbles) is asynchronous and the handler uses evt.currentTarget. currentTarget should be cached locally because the event object is reused in the bubbling chain (codepen).
const clickHandler = evt => {
const {currentTarget} = evt // cache property locally
setTimeout(() => {
console.log('evt.currentTarget changed', evt.currentTarget !== currentTarget)
}, 3000)
}
If you use React, from v17, react drops the Event Pooling.
Therefore, the event object is refreshed in the handler and can be safe to use in asynchronous calls (codepen).
↑is not always true. onClick event's currentTarget is undefined after the event handler finishes. In conclusion, always cache the event's properties locally if you are going to use them after a synchronous call.
From react docs
Note:
As of v17, e.persist() doesn’t do anything because the SyntheticEvent
is no longer pooled.
And many other things that are too long to be pasted in an answer, so I summarized and made a blog post here.
If this isn't sticking, try this:
current in currentTarget refers to the present. It's the most recent target that caught the event that bubbled up from elsewhere.
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<form onclick="alert('form')">FORM
<div onclick="alert('div')">DIV
<p onclick="alert('p')">P</p>
</div>
</form>
If click on the P tag in above code then you will get three alert,and if you click on the div tag you will get two alert and a single alert on clicking the form tag.
And now see the following code,
<style>
body * {
margin: 10px;
border: 1px solid blue;
}
</style>
<script>
function fun(event){
alert(event.target+" "+event.currentTarget);
}
</script>
<form>FORM
<div onclick="fun(event)">DIV
<p>P</p>
</div>
</form>
We just removed onclick from the P and form tag and now when we click we on P tag we get only one alert:
[object HTMLParagraphElement] [object HTMLDivElement]
Here event.target is [object HTMLParagraphElement],and event.curentTarget is [object HTMLDivElement]:
So
event.target is the node from which the event originated,
and
event.currentTarget, on the opposite, refers to the node on which current-event listener was attached.To know more see bubbling
Here we clicked on P tag but we don't have listener on P but on its parent element div.
Event.currentTarget is the element to which the event handler has been
attached, as opposed to Event.target, which identifies the element on
which the event occurred and which may be its descendant.
Source: MDN
target always refers to the element in front of addEventListener - it's the element on which the event originated.
currentTarget tells you - if this is an event that's bubbling - the element that currently has the event listener attached (which will fire the event handler if the event occurs).
See this CodePen for an example. If you open up developer tools and click the square, you'll see that first the div is the target and the currentTarget, but the event bubbles up to the main element - then main element becomes the currentTarget, while the div is still the target. Note the event listener needs to be attached to both elements for the bubbling to occur.
event.target is the node from which the event originated, ie. wherever you place your event listener (on paragraph or span), event.target refers to node (where user clicked).
event.currentTarget, on the opposite, refers to the node on which current-event listener was attached. Ie. if we attached our event listener on paragraph node, then event.currentTarget refers to paragraph while event.target still refers to span.
Note: that if we also have an event listener on body, then for this event-listener, event.currentTarget refers to body (ie. event provided as input to event-listerners is updated each time event is bubbling one node up).
Here's a simple scenario to explain why it's needed. Let's say there are some messages that you show to the user with the format below, but you also want to give them the freedom to close them (unless you have a special mental disorder), so here are some message panes:
[ A message will be in this pane [x] ]
[ A message will be in this pane [x] ]
[ A message will be in this pane [x] ]
and when the user clicks on the [x] button on each, the whole corresponding pane must be removed.
Here's the HTML code for the pane:
<div class="pane">
A message will be here
<span class="remove-button">[x]</span>
</div>
Now where do you want to add the click event listener? The user clicks on [x], but you want to remove the pane, so:
If you add the click event listener to the [x], then you will have to find its parent on DOM and remove it... which is possible but ugly and "DOM dependent".
And if you add the click event listener to the pane, clicking "everywhere on the pane" will remove it, and not just clicking on its [x] button.
So what can we do? We can use the "Bubbles Up" feature of the event system:
"Events are raised and bubble up the DOM tree regardless of the existence of any event handlers."
In our example, this means that even if we add the event handlers to the panes, we will be able to catch the events raised specifically by the [x] button clicks (because events bubble up). So there can be difference between where an event is raised, and where we catch and handle it.
Where it's raised will be in the event.target, and where it's caught will be in the event.currentTarget (where we're currently handling it). So:
let panes = document.getElementsByClassName("pane");
for(let pane of panes){
pane.addEventListener('click', hndlr);
}
function hndlr(e){
if(e.target.classList.contains('remove-button')){
e.currentTarget.remove();
}
}
(The credit of this example goes to the website JavaScript.info)
An experiment:
document.addEventListener("click", (e) => {
console.log(e.target, e.currentTarget);
});
document.querySelector("p").click();
output:
<p></p>
#document
The target (<p></p>) seems to be the element clicked, while the currentTarget (#document) is the element that is listening for the click event.

Delegated events don't work in combination with :not() selector

I want to do something on all clicks except on a certain element.
I've created a very simple example which demonstrates the issue: http://jsfiddle.net/nhe6wk77/.
My code:
$('body').on('click', ':not(a)', function () {
// do stuff
});
I'd expect all click to on <a> to be ignored, but this is not the case.
Am I doing something wrong or is this a bug on jQuery's side?
There's a lot going on in that code that's not obvious. Most importantly, the click event is actually attached to the body element. Since that element isn't an anchor, you'll always get the alert. (Event delegation works because the click event bubbles up from the a through all its ancestors, including body, until it reaches document.)
What you want to do is check the event.target. That will tell you the element that was actually clicked on, but the actual click event is still bound to the body element:
$('body').on('click', function (e) { // e = event object
if ($(e.target).is(':not(a)')) {
alert('got a click');
}
});
http://jsfiddle.net/y3kx19z7/
No this is not a bug but rather intended behaviour.
The event bubbles all the way up. By clicking the a node, you are still triggering it's parents event from the div node.
Read more about event bubbling in the W3C DOM Specification. Just search for "bubble".
You need to stop the event propagation of the a nodes. i.e.:
$('body').on('click', ':not(a)', function () {
// do something effectively
alert('you should not see me when clicking a link');
});
$("a").click(function( event ) {
// do nothing effectively, but stop event bubbling
event.stopPropagation();
});
JSFiddle: http://jsfiddle.net/nhe6wk77/6/
It's working as intended, here's why!
Use of the :not() selector is honored in delegated events, but it's an uncommon practice because of how events bubble up the DOM tree potentially triggering the handler multiple times along the way.
The jQuery API Documentation states that:
jQuery bubbles the event from the event target up to the element where the handler is attached (i.e., innermost to outermost element) and runs the handler for any elements along that path matching the selector.
Notice the phrase "and runs the handler for any elements along that path matching the selector".
In your example, jQuery is accurately not running the handler on the a element, but as the event bubbles up the tree, it runs the handler for any element that matches :not(a), which is every other element in the path.
Here is a clear example showing how this works: http://jsfiddle.net/gfullam/5mug7p2m/
$('body').on('click', ':not(a)', function (e) {
alert($(this).text());
});
<div class="outer">
<div class="inner">
Click once, trigger twice
</div>
</div>
<div class="outer">
<div class="inner">
<button type="button">Click once, trigger thrice</button>
</div>
</div>
Clicking on the link in the first block of nested divs, will start the event bubbling, but the clicked a element — a.k.a. the event target — doesn't trigger the handler because it doesn't match the :not(a) selector.
But as the event bubbles up through the DOM, each of its parents — a.k.a the event currentTarget — triggers the handler because they do match the :not(a) selector, causing the handler to run twice. Multiple triggering is something to be aware of since it may not be a desired result.
Likewise, clicking on the button in the second block of nested divs, will start the event bubbling, but this time the event target does match the :not(a) selector, so it triggers the handler immediately. Then as the event bubbles up, each of its parents matching the selector triggers the handler, too, causing the handler to run three times.
As others have suggested, you need to either bind an alternate handler that stops propagation on a click events or check the event target against the :not(a) selector inside your handler instead of the delegated selector.
$("body").click(function(e) {
if($(e.target).is('a')){
e.preventDefault();
return;
}
alert("woohoo!");
});
check the target of the click. this way you dont need to bind another event.
updated fiddle

Capturing and Bubbling using jQuery

I am new to jQuery and I‘m trying to understand the concept of capturing and bubbling.
I have read a lot of articles, but most of them described event propagation for Javascript.
Lets assume we have the following HTML code:
<div id="outer">
outer
<div id="inner">
inner
</div>
</div>
Capturing is the phase where we go down the DOM elements and bubbling is when we go up.
In Javascript you can decide which way to follow (using true or false parameters):
element.addEventListener('click', doSomething, true) --> capture phase
element.addEventListener('click', doSomething, false) --> bubble phase
Is there anything similar for jQuery to denote which way to follow other than the JavaScript way?
Also does jQuery uses a default phase? For example bubble?
Because i used the following code to test this:
css
<style>
div {
border: 1px solid green;
width: 200px;
}
</style>
jQuery
<script>
$(document).ready(function(){
$('div').click(function(){
$(this).animate({'width':'+=10px'},{duration: 3000})
});
});
</script>
It appears that when I click on the outer div, only that div animates to a larger div. When I click to the inner div both divs animate to larger divs.
I don’t know if I am wrong, but this test shows that the default browser propagation method is bubble.
Please correct me if I’m wrong.
jQuery only uses event bubbling. If you want to add an event handler that uses the capturing model, you have to do it explicitly using addEventListener, with the third argument true as you show in the question.
Event bubbling which will start executing from the innermost element to the outermost element.
Event Capturing which will start executing from the outer element to the innermost element.
But jQuery will use event bubbling. We can achieve event capturing with:
$("body")[0].addEventListener('click', callback, true);
The 3rd parameter in the addEventListener which will tell the browser whether to take event bubbling or event capturing.
By default it is false.
If it is false then it will take event bubbling.
If it is true then it will take event capturing.
Question and answers live with the following misconception: that the browser does either capture or bubble.
Truth is: the browser does always both, capture and bubble, on every click, in that order.
Is there anything similar for jQuery to denote which way to follow other than the JavaScript way?
Also does jQuery uses a default phase? For example bubble?
jQuery has no event phases. The DOM has. And the DOM does always both.
But jQuery registers handlers only to the bubble phase. There is no jQuery way to register to the capture phase, so bubble registration is not a default, it is the only way (with jQuery).
I don’t know if I am wrong, but this test shows that the default browser propagation method is bubble.
You are wrong, if I’m allowed to say. When you click on the outer div, capture happens, until it reaches the outer div, then bubble... It just does not go any deeper than the actual target of the event.
If you click the inner div, capture passes the outer div, but no handler is registered there for that phase, then it reaches the target, and on the way back up (bubble) it triggers the outer div handler.—I haven’t run your code, but it would be hard to tell which one happened first (the inner is first).
(Note: once the target is reached, the phase is actually called “target phase” and handlers are called independent of which phase they registered for (in registration order, btw).)
Every Event is going first through "capturing" phase and then through "bubbling" phase.
For instance, when user clicks on <a>, all event handlers bound using "capturing" (third argument in addEventListener method set to true, not supported in jQuery) are called starting from outermost <html> all the way down to the link. Then, the "bubbling" phase starts and all event handlers using "bubbling" (supported in jQuery) are called the opposite way - from link back to the <html>.
You can try it on your own, firing this code in developer tools and clicking anywhere on your site.
document.querySelectorAll("*").forEach(it => {
it.addEventListener("click", function() {console.log("capturing: ", it)}, true);
it.addEventListener("click", function() {console.log("bubbling: ", it)}, false);
});
The event is triggered in event bubbling on the element on to which the user has clicked,and unless we call .stopPropagation() on the event object the event is then triggered all the way up the DOM.
Default is event bubbling set in Jquery in order to use Capture ypu need to set parameter as true in .addEventListner

Categories

Resources