'Why does the form submit event fire when I have stopped propagation at the submit button level?

HTML

<form>
    <input type='text'>
    <button type='submit'>Submit</button>
</form>

JavaScript

$('form').on('submit', function(e) {
    alert('submit');
    e.preventDefault();
});

$('button').on('click', function(e) {
    e.stopPropagation();
    alert('clicked');
});

Fiddle


After watching the great video here, I understand that when I click the submit button, the event bubbles up to the form, and the form's submit event is then triggered. Which explains why "clicked" is alerted before "submit" (before I add e.stopPropagation() to the button handler).

But when I add e.stopPropagation() to the button handler, "submit" is still alerted. Why? I thought that stopPropagation prevents the event from bubbling up to the form, and so the form.on('submit') listener shouldn't be "hearing" an event.



Solution 1:[1]

When you click a submit button in a form the click event spawns on the button and bubbles up. The submit event spawns on the form (not the button) and bubbles up from there.

If you stop propagation on the click event you're just stopping the bubbling phase of the click event. This has no effect on the submit event.

To stop the submit action you have to add a check to the submit handler.

Keep in mind that adding e.preventDefault() on the click handler in the button is not enough to prevent the submit event from spawning since there are more ways to submit a form than just clicking a button. (pressing enter in an input field for instance).

Solution 2:[2]

See the handler

$('button').on('click', function(e) {
    e.stopPropagation();

Note that the event is click, so you're stopping the click event from propagating up the chain, and that doesn't interact with the submit event at all, that still fires as the default action of a submit button is to submit the form, and the way to stop that is to prevent that default action with preventDefault

In other words, stopPropagation only stops the current event being handled from propagating to parent elements, it does not stop the default behaviour of the element, that would be preventDefault !

Solution 3:[3]

You need e.preventDefault(); in the button click as well:

$('form').on('submit', function(e) {
    alert('submit');
    e.preventDefault();
});

$('button').on('click', function(e) {
    e.preventDefault();
    alert('clicked');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<form>
    <input type='text'/>
    <button type='submit'>Submit</button>
</form>

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 adeneo
Solution 3