If I append a child element to a parent element, is it possible to stop the propagation of the parent's event to the appended child if I don't have access to the parent element's event listener code? If it's even possible, how?
Is there a way to do this inside the child event listener? Is there something like e.target.parentElement.stopPropagation()?
If the event passes through the child you appended, you can stop it by calling stopPropagation on it. It has nothing to do with what element's handler does that; all that matters is that one of them calls that method on the event. So just e.stopPropagation().
If the event doesn't pass through the child (it's directly targeted at the parent, or passes through some other child to the parent), you can't stop propagation of it unless you can attach your handler to the parent element before the other handler is attached. But from your description, it doesn't sound like you can do that.
It is perfectly clear that event.target deals with the DOM element that initiated the event.
And - event.delegateTarget provides the DOM element where we actually attached the listener ,
But I'm having trouble to understand when would I use - event.currentTarget :
Looking at jQuery samples which shows this example : JSBIN1
It seems like it is the exact same as event.delegateTarget
$( "body" ).click(function( event ) {
$( "#log" ).html( "clicked: " + event.currentTarget.nodeName );
});
Everywhere I click - it says : clicked "BODY" - which is exactly like the delegateTarget's behaviour
Question
In Which (real life) scenarios would I use event.currentTarget? ( example would be much appreciated)
nb - couldn't find any currentTarget vs delegateTarget questions....
event.target and event.currentTarget are attributes of Event interface defined by W3C spec:
event.target:
This property of event objects is the object the event was dispatched
on. It is different than event.currentTarget when the event handler is
called in bubbling or capturing phase of the event.
event.currentTarget:
Identifies the current target for the event, as the event traverses
the DOM. It always refers to the element the event handler has been
attached to as opposed to event.target which identifies the element on
which the event occurred.
Additionally, jQuery adds event.delegateTarget:
The element where the currently-called jQuery event handler was attached
The difference with event.currentTarget is explained in
This property is most often useful in delegated events attached by
.delegate() or .on(), where the event handler is attached at an
ancestor of the element being processed. It can be used, for example,
to identify and remove event handlers at the delegation point.
For non-delegated event handlers attached directly to an element,
event.delegateTarget will always be equal to event.currentTarget.
For example, if you click the button in the following HTML:
<div class="box">
<button>Button</button>
</div>
$( "body" ).on( "click", ".box", function(e) {
e.delegateTarget; // body
e.currentTarget; // .box
e.target; // button
});
If you have HTML markup as shown below
<a href="http://www.someurl.com" data-ajax="true" data-id="345">
<img src="company.jpg"/>
</a>
And you have bind handler to anchor
$("a").click(function(){
// Some stuff
});
Now here in the click handler event.target points to the image but you have actually clicked on anchor and in the click handler you need to access the data-id attribute of anchor to perform some action. here to get the current target you can use event.currentTarget to access the anchor.
The event.currentTarget property is the element that is currently responding to the DOM event, which is the element you bound the event handler to. As for a real world usage? Not really sure.
I have the following code:
document.oncontextmenu = function(evt) {
evt = evt || window.event;
console.log(evt.target, evt.toElement, evt.srcElement);
};
By clicking the right mouse button on a <div class="foo"></div>, returns this:
div.foo, div.foo, div.foo
By clicking the right mouse button on a <input>, returns this:
input, input, input
All seem to bring the same result. Is there any situation that one of them has different use than the others?
The event target is the element to which the event is dispatched:
The object to which an event is targeted using the DOM event
flow. The event target is the value of the Event.target
attribute.
srcElement is a IE non-standard way to obtain the target.
The current event target is the element which has the event listener which is currently invoked:
In an event flow, the current event target is the object associated
with the event handler that is currently being dispatched. This
object MAY be the event target itself or one of its ancestors.
The current event target changes as the event propagates from
object to object through the various phases of the event flow.
The current event target is the value of the
Event.currentTarget attribute.
Using this inside an event listener is a common (and standard) way to obtain the current event target.
Some kind events have a relatedTarget:
Used to identify a secondary EventTarget related to a UI event,
depending on the type of event.
fromElement and toElement are IE non-standard ways to obtain the relatedTarget.
It's an audio player: the idea is that the play button turns into a pause button (and viceversa) when clicked.
Thing is that the .pause event doesn't trigger the following function:
$('.pause').click(function(){
player.pause();
$(this).addClass('play');
$(this).removeClass('pause');
});
The css shows that the pause class is set, but the function doesn't work. Is there a way to make it work? (would be great to know why it didn't work)
jsFiddle
Use a delegated event binding to bind a handler that will be selector-aware without requiring rebinding on events.
For the purposes of your demo, the selector would be along the lines of:
$('.player_controls').on('click', '.pause', function () {...});
Delegate event bindings attach the listener to a parent element that checks to see if the event fired was fired on an element that matches the provided selector.
jQuery docs
When a selector is provided, the event handler is referred to as delegated. The handler is not called when the event occurs directly on the bound element, but only for descendants (inner elements) that match the selector. 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.
Event handlers are bound only to the currently selected elements; they must exist on the page at the time your code makes the call to .on(). To ensure the elements are present and can be selected, perform event binding inside a document ready handler for elements that are in the HTML markup on the page. If new HTML is being injected into the page, select the elements and attach event handlers after the new HTML is placed into the page. Or, use delegated events to attach an event handler, as described next.
Delegated events have the advantage that they can process events from descendant elements that are added to the document at a later time. By picking an element that is guaranteed to be present at the time the delegated event handler is attached, you can use delegated events to avoid the need to frequently attach and remove event handlers. This element could be the container element of a view in a Model-View-Controller design, for example, or document if the event handler wants to monitor all bubbling events in the document. The document element is available in the head of the document before loading any other HTML, so it is safe to attach events there without waiting for the document to be ready.
You can use event delegation for this. The issue is that binding directly (without delegation) binds to whichever elements exist at the time click is called.
$(".player_controls").on("click", ".pause", function(){
/* ... */
});
Instead of using $('.pause').click(function(){...}) you would need to start using the $.on method to start listening for objects which are still not in the DOM.
e.g
$(".pause").parent().on("click",".pause", function(event){
player.pause();
$(this).addClass('play');
$(this).removeClass('pause');
});
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.