Reputation: 151
I am seeking to perform a basic form post, but the following submits to the server twice in Chrome and Safari (but behaves as expected in Firefox):
<form id="create-deck-form" action="/decks/create" method="post">
<fieldset>
<legend>Create new deck</legend>
<label for="deck-name-field">Name</label>
<input id="deck-name-field" name="deck-name-field" type="text" value="" maxlength="140" />
<label for="tag-field">Tags</label>
<input id="tag-field" name="tag-field" type="text" value="" maxlength="140" />
<input class="add-button" type="submit" value="Create" />
</fieldset>
</form>
I would like to use the onsubmit
attribute to perform validation on the fields before submission, but wherever the return value is true
, the form is submitted twice.
I have sought to bind a jQuery handler to the form, but here too, where the default behaviour is not prevented, the form is submitted twice, e.g.:
<script type="text/javascript">
$(document).ready(function() {
$("#create-deck-form").submit(function(event){
if($("#deck-name-field").val() == "") {
event.preventDefault();
alert("deck name required");
}
});
});
</script>
While I suppose there is something blindingly obvious wrong here to a fresh pair of eyes, I am deeply confused why submission, with or without validation, makes a duplicate post to the server in Chrome and Safari. I'd be grateful for any insight.
Upvotes: 7
Views: 9344
Reputation: 11
Browsers (Safari Desktop for instance) mask form submit events as click events. So you might run into an issue of forms being submitted even if you have an evt.preventDefault()
or evt.stopPropagation()
set on your form's submit event.
Good example and scenario for this is submitting a form by hitting the ENTER key. In that case Safari emits a click event that might cause other event listeners to fire, etc.
Solution:
You can listen to those masked submit events like this:
$('[type="submit"]', $('form')).on('click', function(evt) {
...
}
Now you only want to catch those events that are actually masked; you don't want to catch a mouseclick on a submit button.
Therefore you have to distinguish real clicks from those rogue ones. You can do so by checking the evt.originalEvent
object.
If you can find a pointerId
(Chrome) key than rogue clicks come with a pointerId = -1
(some negative value); if you don't have a pointerId
(eg. Safari) you can look for the evt.originalEvent.detail
key (Safari) which in case of rogue clicks comes with the value of 0 (zero).
Full Example
$('[type="submit"]', $('form')).on('click', function(evt) {
let do_not_submit = false
// chrome
if (typeof evt.originalEvent.pointerId !== 'undefined' && evt.originalEvent.pointerId < 0) {
do_not_submit = true
}
// safari
if (!do_not_submit && typeof evt.originalEvent.detail !== 'undefined' && evt.originalEvent.detail === 0) {
do_not_submit = true
}
if (do_not_submit) {
evt.preventDefault()
evt.stopPropagation()
return
}
// no worries ...
// submitting ...
}
Upvotes: 1
Reputation: 151
This issue is actually associated with Facebox (http://defunkt.github.com/facebox/). Facebox initialization causes a second set of requests after your page loads. So, if you post to /myaction/create
, Facebox will start a second set of requests with the base URL set to /myaction/create
. A fix is to redirect to a URL which handles get requests after doing a post, so you don't end up performing the post twice. Thanks very much for your help.
Upvotes: 3
Reputation: 3167
Ok, not sure how much this will help, but try removing the submit input and submitting the form via javascript. So for instance
<input id="submit-button" class="add-button" type="button" value="Create" />
Then instead of listening to the onsubmit, you can try
$('#submit-button').click(function(evt) {
if(validationSuccess(...)) {
$("#create-deck-form").submit();
} else {
//display whatever
}
});
Now you're way should work too... but this way you can debug where you're problem is.... This should only submit once... good luck!
Upvotes: 0
Reputation: 235962
I'm not 100% sure, but please try this one:
<script type="text/javascript">
$(document).ready(function() {
$("#create-deck-form").submit(function(event){
if(!$("#deck-name-field").val().length) {
return false;
}
});
});
</script>
if that does not work, please have a look at
for(e in $("#create-deck-form").data('events'))
alert(e);
This will alert you all events which are bound to your form
. Maybe there are more event handlers? Otherwise also alert/log
$("#create-deck-form").attr('onclick')
and
$("#create-deck-form").attr('onsubmit')
just in case.
Upvotes: 1
Reputation: 3686
Can you try return false;
after your alert and remove event.preventDefault();
. Maybe you also need return true;
in your else-clause. I believe I have that working somewhere.
Upvotes: 0