I created a little Snippet to demonstrate the issue:
$(document).ready(function() {
// Registering form-submission as the first would be a possibility
$('form').on('submit', function(e) {
console.log(e.target);
console.info('My first callback is executing');
// Do some stuff here, but don't mess with the event-object
// (like preventing default or stopping the event-chain)
});
// Then afterwards everything else that *might* catch the event
$('form').on('submit', function(e) {
console.log(e.target);
console.info('My second callback is executing');
// Usually some Ajax-Handler-Callback, that handles sending the form,
// will preventDefault() and stopImmediatePropagation() - that is why
// your general first listener must be registered before any of these callbacks
console.warn('Second callback stops the event from bubbling/propagating');
e.stopImmediatePropagation();
e.preventDefault();
});
// This will never happen
$('form').on('submit', function(e) {
console.log(e.target);
console.info('My third callback will never execute');
});
// Using a delegated event-listener with `useCapture` lets this execute first
document.addEventListener('submit', function(e) {
console.info('Capturing the event natively');
}, true);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h1>My Website with a multi-handled form</h1>
<form class="" action="" method="post">
<input type="text" name="test" value="">
<button type="submit" name="button">Send</button>
</form>
Output of the Snippet, when submitting the form:
Capturing the event natively
<form class action method="post">…</form>
My first callback is executing
<form class action method="post">…</form>
My second callback is executing
Second callback stops the event from bubbling/propagating
What did just happened?
By pressing the submit-button, our form emits the submit-event. The Browser starts with the event-propagation in a specified event-order. There are two phases of event-propagation: event-capturing and event-bubbling.
Now our first called event-listener is the one with the useCapture-directive.
This is during the capture-phase of the event-propagation.
Explanation for useCapture taken from MDN:
capture: A Boolean that indicates that events of this type will be
dispatched to the registered listener before being dispatched to any
EventTarget beneath it in the DOM tree.
When done, the Browser starts with the bubbling-phase of the event-propagation.
This is where all $('element').on()
and element.addEventListener()
(without the useCapture option) registered listeners are called in their appearing order.
During this phase our second listener is not only preventing default (not submitting the form the standard-way), but also stopping the event-propagation by calling e.stopImmediatePropagation()
.
After that the event-chain/event-propagation stops immediately.
That is why our third listener will never execute.
On a side note: When using jQuery and exiting an event-callback with
return false
, jQuery will execute e.preventDefault()
and
e.stopPropagation()
automatically.
See: http://api.jquery.com/on/
Conclusion
You basically have two possibilities for your scenario:
Register your default general event-listener before anything else (first event-registration in Snippet).
Register an event-listener during the capture-phase, to capture the event and handle things before the other listeners from the bubbling-phase get called (last event-registration in Snippet).
With both methods you should be able to do your stuff without interfering with other event-listeners.