Use the event capture phase
Put an element around the element you want to cancel the click event for, and add a capture event handler to it.
var btnElm = document.querySelector('button');
btnElm.addEventListener('mouseup', function(e){
console.log('mouseup');
window.addEventListener(
'click',
captureClick,
true // <-- This registeres this listener for the capture
// phase instead of the bubbling phase!
);
});
btnElm.addEventListener('click', function(e){
console.log('click');
});
function captureClick(e) {
e.stopPropagation(); // Stop the click from being propagated.
console.log('click captured');
window.removeEventListener('click', captureClick, true); // cleanup
}
<button>Test capture click event</button>
What happens:
Before the click event on the button
is triggered the click event on the surrounding div
gets fired because it registered itself for the capture phase instead of the bubbling phase.
The captureClick
handler then stops the propagation of it’s click
event and prevents the click
handler on the button to be called. Exactly what you wanted. It then removes itself for cleanup.
Capturing vs. Bubbling:
The capture phase is called from the DOM root up to the leafs while the bubbling phase is from the leafs up the root (see: wonderful explanation of event order).
jQuery always adds events to the bubbling phase that’s why we need to use pure JS here to add our capture event specifically to the capture phase.
Keep in mind, that IE introduced the W3C’s event capturing model with IE9 so this won’t work with IE < 9.
With the current Event API you can’t add a new event handler to a DOM Element before another one that was already added. There’s no priority parameter and there’s no safe cross-browser solution to modify the list of event listeners.