Which of these examples is more correct?
window.addEventListener('scroll', someFunc, false);
window.addEventListener('scroll', someFunc);
I know what is bubbling, it moves up from element to window. But what about any events on window – should we use callback false for this or not?
It looks like nonsense in this case, because the event has nowhere to go up, but I want to be sure.
The third parameter useCapture specifies whether the event should be executed in the capturing or in the bubbling phase.
If it should be executed later than element event handlers, you have to use false(default).
If it should be executed earlier than element event handlers, you have to use true.
If no child elements have event listener, you can ignore the useCapture parameter.
Related
I can get elements to execute their handlers in the capturing phase like so:
elem.addEventListener('event', handler, {once: false, capture: true});
Setting the third argument to true also works - any obvious reason why? Does doing it this way have any side-effects?
The boolean parameter was the original way how it worked, before the options object was introduced. That's the reason why it (still) works: for backwards compatibility.
See docs:
Syntax
target.addEventListener(type, listener [, options]);
target.addEventListener(type, listener [, useCapture]);
You can either pass a boolean useCapture (this exists for a longer time already) or an options object which allows you to specify capture too but other things as well (e.g. once).
So, addEventListener(..., true) is the same as addEventListener(..., { capture: true }), and there are no side-effects.
The options object form exists since ~2016. Check on caniuse to see which clients support it.
If you don't have other event listeners that may do stuff to the event or page, then it generally doesn't matter where you attach your listener. If this is the only listener, you can attach it to the element, or one of its parents, or to the document or window, and to any of those in the bubbling phase or capturing phase - and it won't make a difference in most cases.
The primary use of a capturing listener is to set the order in which event handlers execute. When an event is dispatched to the element, it first captures downward from the window, firing capturing listeners on the window, then on the document, then on intermediate elements, until it reaches the deepest element that resulted in the event. At the deepest element, both capturing and bubbling listeners will run, in the order they were attached. Then, the event will start "bubbling" up, triggering bubbling listeners on that deepest element, then on intermediate elements, then on the document, and then on the window.
To illustrate, see how the capturing listener runs first here, when the listeners are attached to a parent:
document.addEventListener('click', () => console.log('bubbling'));
document.addEventListener('click', () => console.log('capturing (method 1)'), true);
document.addEventListener('click', () => console.log('capturing (method 2)'), { capture: true });
<button>click</button>
If the element the listener is being attached to is the same element that dispatches the event (for example, if you have a button with no children, which gets clicked), then capturing vs bubbling has no effect - all listeners will run in the order they were attached, regardless of useCapture.
Bubbling listeners can be used to prevent the event from bubbling upward and triggering parent listeners. Similarly, capturing listeners can prevent the event from capturing downward and triggering child listeners.
window.addEventListener('click', (e) => {
e.stopPropagation();
console.log('capturing, stopPropagation')
}, true);
document.querySelector('button').addEventListener('click', () => console.log('at target'));
<button>click</button>
Above, the capturing listener called stopPropagation on the event, preventing it from propagating downward to the child listener, which would've run later were it not for stopPropagation.
For the third argument to addEventListener, you can either use { capture: useCapture } or just useCapture as the argument, per the specification:
The addEventListener(type, callback, options) method, when invoked, must run these steps:
Let capture, passive, and once be the result of flattening more options.
Where "flattening more" does:
Let capture be the result of flattening options.
Where "flattening" does:
If options is a boolean, then return options.
Return options’s capture.
I have defined this event handler:
document.addEventListener("load", function(){
alert("Called on page load");
}, false);
I noticed it does not get called when the boolean flag is set to false(fire at bubble phase). Could someone help me out on why this is the case.
When an event is being sent to an element, it descends the document tree in the capture phase until it reaches the target. Then, if it’s a bubbling event, it bubbles back up.
From 2.1 Introduction to “DOM Events” in the DOM standard:
When an event is dispatched to an object that participates in a tree (e.g. an element), it can reach event listeners on that object’s ancestors too. First all object’s ancestor event listeners whose capture variable is set to true are invoked, in tree order. Second, object’s own event listeners are invoked. And finally, and only if event’s bubbles attribute value is true, object’s ancestor event listeners are invoked again, but now in reverse tree order.
load isn’t a bubbling event, and – here’s the important part – it doesn’t target document. When you add a capture listener, you’re really getting load events from parts of the document’s content that normally receive the event, like scripts or images. On a page with only the script, you won’t see the listener get called at all:
<iframe srcdoc="<script>document.addEventListener('load', () => { alert('loaded'); }, true);</script>"></iframe>
And on a page with load events that fire after the listener is attached, like this Stack Snippet that includes <style>s, you’ll see it more than once:
let i = 0;
document.addEventListener('load', e => {
console.log(`loaded ${++i}: ${e.target.nodeName}`);
}, true);
You probably meant to add a non-capturing listener to window instead of document, because window is something that receives a load event, unlike document. (Or you might have meant something else. There’s a lot of ways to interpret “page load”. See Window: load event on MDN for details on what the load event means on window and alternatives if it wasn’t what you intended.)
window.addEventListener("load", function() {
alert("Called on page load");
}, false);
I'm looking for a way in JS to stop a click event from continuing down the DOM to a nested child element (capture phase) when the parent element was clicked.
It would be the inverse of the e.stopPropogation() function to prevent a click event from bubbling up.
Is there a native JS function for this?
Edit 03/10
Link to example
Edit 03/11
Typo in the function call - it's stopPropagation(), not stopPropogation(). Thanks to #JackPattishall for the find.
yes there is native js function for capturing event in capture phase.
In all browsers, except IE<9, there are two stages of event processing.
The event first goes down - that’s called capturing, and then bubbles up. This behavior is standartized in W3C specification.
All methods of event handling ignore the caputiring phase. Using addEventListener with last argument true is only the way to catch the event at capturing.
elem.addEventListener( type, handler, phase )
phase = true
The handler is set on the capturing phase.
phase = false
The handler is set on the bubbling phase.
For better understanding of event capturing and bubbling you can follow this link
okey, One thing you and do is use the stopPropogation() at the top in Dom.
eg. you have a table(#table1) and elements(tr,td).
so, if i do:
table1.addEventListener("click",function(event){
event.stopPropagation();
console.log(this);
},true);
tableElem[2].addEventListener("click",function(event){
console.log(this);
});
tableElem[2].addEventListener("click",function(event){
console.log("hii");
});
The event will be intercepted at top and propogation will be stopped.
stopPropogation() stops propagation irrespective of on which step event is intercepted.
For example we have a page with a link that has onclick event listener on it. But handler makes stopPropagation. How I can handle that click event was made, if it's not bubble to root anymore?
e.g.
document.addEventListener('click', function(e) {console.log(e);});
a.onclick = function(e) {e.stopPropagation();};
DOM event propagation works in three phases: the capture phase, the target phase and the bubble phase. Roughly, the event first works its way down to the target, reaches the target and then works its way back up.
By default, event handlers are attached in the final bubble phase. If you attach a click event listener in the first capture phase, it will run before the previous handler has had the chance to call stopPropagation.
See this question for a deeper explanation.
The simple answer is, add a third argument, true, when adding your event listener.
document.addEventListener('click', someFunction, true)
This flag (called useCapture) will call someFunction on all clicks in a document, even when the user clicked inside an element with a click handler that called event.stopPropagation.
With options
If you're already passing an object of options as the third argument, simply include capture: true in them:
document.addEventListener('click', someFunction, { capture: true, ...someMoreOptions })
Why?
Enabling the handler's useCapture mode like this means the listener listens during the earlier "capture" phase of the event (which starts at the outmost element then trickles down through children), instead of the later "bubble" phase (which starts at the innermost element and bubbles back up through ancestors, and is the one stopPropagation blocks).
Side effects
That also means that applying this setting changes the timing: your capture phase click event will occur before any click events of either type inside child or descendant elements.
For example, in the above function, if a user clicks on a button on the page, the someFunction attached to the document's capture phase will be called before any handlers attached to the button; whereas without setting use capture to true, you'd expect it to be called after.
How do i attach multiple event handlers to addEventListener() method
For eg:
elem.addEventListener("mouseover",handlers....,false/true);
I also wanted to know how the bubbling when set to false and capturing when set to true on the 3rd parameter does in the dom tree.
Event bubbling means that when an event is triggered on an element, this element's parent is then checked for an event of the same time. If one exists, it is also triggered. This process is then repeated all the way up through the DOM tree. I believe that bubbling events will also make use of capturing (see below) before the bubbling process.
Capturing starts from the root and traverses the DOM tree down to the target element, triggering events of the target's type on the way.
For a better understanding of this, you can find more information here.
As for your first question, it has been a while since I worked with this, so therefore I do not remember a way to do what you want in one statement. However, you could do something like this:
myElement.addEventListener('click', myFunction1, false);
myElement.addEventListener('click', myFunction2, false);