Event Capture
Basic:
document.querySelector('a[href^="tel:"]').addEventListener('click',function(evt){
console.group('Click to Call Link Clicked. Details:');
console.log(evt);
console.groupEnd();
});
JQuery:
$('a[href^="tel:"]').on('click',function(evt){
console.group('Click to Call Link Clicked. Details:');
console.log(evt);
console.groupEnd();
});
Bubbling and capturing:
- Excellent Guide - Javascript.info
@TODO
Attaching Directly vs Letting Bubble
Often you will event listeners attached at the document level, wait for an event to bubble up, and then check to see if the event matches what you are looking for. Here are some examples of that pattern:
- Vanilla JS
document.addEventListener('click',function(evt){
if (evt.target.getAttribute('id')==='ctaLink'){
console.log('My CTA Link Clicked!');
}
});
- JQuery
$(document).on('click','#ctaLink',function(evt){
console.log('My CTA Link Clicked!');
});
Problems with this method:
The main problem with this method has to do with bubbling and capture. Consider this code:
<!-- Script from third party vendor -->
<script>
document.querySelector('#ctaLink').addEventListener('click',function(evt){
evt.stopPropagation();
});
</script>
<!-- Your event listener -->
<script>
document.addEventListener('click',function(evt){
if (evt.target.getAttribute('id')==='ctaLink'){
console.log('My CTA Link Clicked!');
// This never logs
}
});
</script>
Because the first script used evt.stopPropagation()
(MDN), once it fires, it will stop the event from bubbling up the DOM and it will never reach our document
listener! However, if we attach our listener directly to the node that fires it (corresponding to evt.target
), side-by-side listeners will still fire, like this:
<!-- Script from third party vendor -->
<script>
document.querySelector('#ctaLink').addEventListener('click',function(evt){
evt.stopPropagation();
});
</script>
<!-- Your event listener -->
<script>
document.querySelector('#ctaLink').addEventListener('click',function(evt){
console.log('My CTA Link Clicked!');
// Success!
});
</script>
Warning: Side-by-side listeners will not work, if one listener callback uses
event.stopImmediatePropagation()
. This method stops all other handlers attached to the DOM node that run after it from firing, and thus should be avoided using whenever possible.
Event Generation
- MDN Guide on creating and dispatching events
You can dispatch native events with JS:
document.querySelector('button').dispatchEvent(new Event('mouseover', {view: window, bubbles: true, cancelable: true}))
But, also your own arbitrary events can be generated with JS and dispatched to the browser/DOM with relative ease:
var customEvent = new Event('videoPlay');
document.getElementById('videoPlayer').dispatchEvent(customEvent);
// Or, dispatch on document
// document.dispatchEvent(customEvent);
For legacy IE support, there is an older way / other APIs. However, strongly not recommended when possible, as deprecated in most browsers.
var customEvent = createEvent('Event');
// initEvent signature is initEvent(eventName, bubbles, cancelable)
customEvent.initEvent('videoPlay',true,false);
document.dispatchEvent(customEvent);
Passing extra details
With CustomEvent (95%+ browser support) (CanIUse)
var customEvent = new CustomEvent('videoProgress',{detail: '25-percent'});
document.getElementById('videoPlayer').dispatchEvent(customEvent);