Introduction
This post falls in the category “Short tricks that I would teach to my younger self”.
Let’s assume that you want to display a confirmation dialog before submitting an important form. You can leverage the Window.confirm()
method, which displays a modal dialog with two buttons, Ok and cancel.
Window.confirm()
returns true if the user clicks on the Ok button.
<form onsubmit="return confirm('Do you really want to submit the form?');">
You can also implement this using jQuery:
$(form).on('submit', function() {
if(confirm('Do you really want to submit the form?')) {
return true;
}
return false;
});
Or more succint:
$(form).on('submit', function() {
return confirm('Do you really want to submit the form?');
});
This simply works out of the box because the confirm()
method blocks the event loop, therefore the form is not submitted until the user clicks one of the two choices.
Now, let’s say that we want to use a nice-looking jQuery plugin, much more appealing to the users, to display the dialog. But when we try to emulate the previous example:
$(form).on('submit', function() {
dialog.confirm({
message: 'Do you really want to submit the form?',
confirm: function() {
return true;
},
cancel: function() {}
});
return false;
});
we notice that the form never gets submitted, due to the asynchronous nature of javascript. Before reaching the confirm
function, the submit
handler returns false, preventing the form to submit. We also cannot do the following:
$(form).on('submit', function() {
dialog.confirm({
message: 'Do you really want to submit the form?',
confirm: function() {
$(form).submit();
},
cancel: function() {}
});
return false;
});
otherwise we are stuck in an infinite loop, where the form never gets submitted.
The solution
The solution is pretty straightforward. We should remove the submit handler on the form as soon as the user confirms his choice. For example we can use the off()
method, which removes an event handler, previously attached with on()
:
$(form).on('submit', function() {
var $this = $(this); // reference to the current scope
dialog.confirm({
message: 'Do you really want to submit the form?',
confirm: function() {
$this.off('submit').submit();
},
cancel: function() {}
});
return false;
});
In this way, the second time the form submission is not intercepted by jQuery.