I have the following jsp:
...
<script type="text/javascript">
$(function() {
// prevent multiple submissions
$('#saveCallListBtn').one("click", function() {
$('#callListForm').submit();
});
});
...
</script>
...
<form:form id="callListForm" commandName="callList" action="${contextPath}/calllist/save" method="POST" htmlEscape="true">
...
<td colspan="2" style="text-align: center">
<input id="saveCallListBtn" type="submit" value="Save" class="button-med"/>
</td>
...
</form:form>
The behavior I am looking for is to only all the form to be submitted once no matter how many times the save button is clicked. Using the jQuery .one function, I can get the above code to correctly work. As the form will submit multiple times if I click more than once.
The following code will work fine:
$('#saveCallListBtn').on("click", function() {
$(this).prop("disabled", true);
$('#callListForm').submit();
});
But I am interested to know what I am doing wrong with the .one function.
Note the type here:
<input id="saveCallListBtn" type="submit" value="Save" class="button-med"/>
A submit button in a form will submit the form, no JavaScript required. So when your handler is automatically removed, on the next click the default handling (submitting the form) occurs, courtesy of the browser.
The only reason you're not seeing the form submitted twice on first click, I suspect, is that the act of submitting the form begins the process of tearing down the page to make room for the result of the submission.
FWIW, I would suggest that you not have a click handler on the button, but rather a submit handler on the form that, if all is well and it's going to allow submission to occur, disables the button and sets a flag to prevent future form submission, since forms can be submitted in multiple ways. (On some forms, pressing Enter in a text field will do it, for instance.)
E.g.:
$("#callListForm").on("submit", function(e) {
var $btn = $("#saveCallListBtn");
var valid = !$btn.prop("disabled");
if (valid) {
// ...do any other validity checks you may want, set `valid` to false
// if problems encountered...
}
if (valid) {
$btn.prop("disabled", true);
} else {
e.preventDefault();
}
});
The jQuery one function will execute the event handler only once. However, the default behaviour of the element clicked will execute indefinitely.
Change the type of the button to button, such that it has no default behaviour:
<input id="saveCallListBtn" type="button" value="Save" class="button-med"/>
Related
I have an input form, with a submit button. I don't want the user to be able to double click the submit button and double submit the form...
So I have added the following jQuery to my Form:
var prevSubmitTime = new Date('2000-01-01');
function preventFromBeingDoubleSubmitted() {
$('form').each(function () {
$(this).submit(function (e) {
if ($("form").valid()) {
var curSubmitTime = new Date($.now());
// prevent the second submit if it is within 2 seconds of the first submit
if (curSubmitTime - prevSubmitTime < 2000) {
e.preventDefault();
}
prevSubmitTime = new Date($.now());
}
});
});
}
$(document).ready(function () {
preventFromBeingDoubleSubmitted();
});
The above code stores the submit time and prevents the second submit, if it is too early (less than 2 seconds), I don't want to permanently disable the submit button, in case there is a server side error...
This code does what I want, but when debugging the code, I can never hit a break point on e.preventDefault();... even if I double click the submit button.
It looks like the second submit event is waiting for the first submit event to complete before firing.
But, if I remove preventFromBeingDoubleSubmitted() function, then I would be able to double submit the form, by double clicking the submit button.
Can anyone explain why sometimes the submit events are fired immediately one after the other... and sometimes it is not the case? Does putting the event handler inside .each(), affects their execution behavior?
Form's when submited by default navigate to the set action url. In the case it isn't explicitly set the url is the current page. The first submit call is going end up starting the navigation process. During this the currently loaded javascript code gets unloaded. This includes event handlers. Hence why you get the inconsistency of being able to double submit or not. If the network request, and other page processes, to the action url happens faster than the speed it takes you to click again the event handlers and your break point won't be called/reached again because they are already unloaded. And vise versa if the network request is slower you would be able to cause the handler to be called and the break point to be reached (if it hasnt already been unloaded).
You say you don't want to permanently disable the submit button, but even if you disable it the form submission is going to cause a page change, and in your example's case this will just load the same page with a new submit button which will not be disabled anymore because its a new page. Thus it is never really permanetly disabeled in the first place.
Now if your real form isn't actually doing a normal form submit, and you are using something like an ajax request, web socket connection, etc then you would set the button to disabled(or set a busy flag) before the request and unset it in the ajax request callback, web socket event,etc.
For example:
jQuery('form').on('submit',function(e){
e.preventDefault();
var fd = new FormData(this);
jQuery('yourbutton').prop('disabled',true);
fetch('url',{method:"post",body:fd}).then(()=>jQuery('yourbutton').prop('disabled',false));
});
In your snippet I've added a few logs that might be helpful. As you are asking more than one question, I'll answer one by one.
var prevSubmitTime = new Date('2000-01-01');
function preventFromBeingDoubleSubmitted() {
$('form').each(function () {
$(this).submit(function (e) {
console.log('I am going to submit form');
if ($("form").valid()) {
var curSubmitTime = new Date($.now());
console.log('I am a valid form')
// prevent the second submit if it is within 2 seconds of the first submit
if (curSubmitTime - prevSubmitTime < 2000) {
console.log('A small time difference. So I am stopping')
e.preventDefault();
}
prevSubmitTime = new Date($.now());
}
});
});
}
$(document).ready(function () {
preventFromBeingDoubleSubmitted();
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-validate/1.19.0/jquery.validate.js"></script>
<form id="myform">
<input type="text" name="q" required="required" />
<br />
<input type="text" name="bar" required="required" />
<br />
<br />
<input type="submit" />
</form>
Can anyone explain why sometimes the submit events are fired
immediately one after the other... and sometimes it is not the case?
I think you've answered this question yourself. You are adding the code to check if there a difference between time you clicked the submit button the first time versus the second time. If the time difference exists, then you stop the second form submit.
I can never hit a break point on e.preventDefault();
The reason you're not able to get the console is, you're redirecting away from that page when you click the submit button. So the console is cleared. If you want to see the console, use an ajax function to submit the form. And on return, you can probably redirect the page somewhere.
Does putting the event handler inside .each(), affects their execution
behavior?
No. It is just an iterator. It will not affect the submit functionality.
I've added a link to the jsfiddle. Adding the alert before preventDefault will stop page from redirecting momentarily. This will prove that the execution happened.
http://jsfiddle.net/2vugwyfe/
You solution is way too overcomplicated. The easiest way to prevent a double submit would be to disable the submit button on submission.
Example:
var submittable = false;
$('form').submit(function (e) {
if (!submittable) {
e.preventDefault();
var $this = $(this);
var $submitButton = $this.find('button[type="submit"]');
$submitButton.attr('disabled', true);
if (CONDITION_SATISFIED) {
submittable = true;
$this.submit()
} else {
$submitButton.attr('disabled', false);
}
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form>
<button type="submit">Submit</button>
</form>
If you add e.preventDefault(); just before doing $("form").valid(), you will see there's an error thrown.
script.js:7 Uncaught TypeError: $(...).valid is not a function
at HTMLFormElement.<anonymous> (script.js:7)
at HTMLFormElement.dispatch (jquery.min.js:2)
at HTMLFormElement.y.handle (jquery.min.js:2)
This error wasn't visible at first because the submit actually changes the page (refreshes the page in this case) if nothing else is implemented.
However, in general the practice is navigating to another page after a form submission.
If you still want to go with your approach and limit the number of submitting, I suggest keeping the submitted state in a local variable and change it according to the validation on the server side.
Last thing.. I don't understand the iteration through the forms since you have only one in your HTML -> $('form').each is useless.
I know what you want, but you made it very complicated. instead of inserting a submit button just add a simple div and add a click handler on that.
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form id="myform">
<input type="text" name="myInput" />
<div id="submit" onclick="myform_submit()" />
</form>
and :
function myform_submit() {
if ($('#submit').hasClass('busy')) { return; }
$('#submit').addClass('busy');
// do the tasks then remove the `busy` class :
$('#submit').removeClass('busy');
}
I just show the idea, you can do better.
in my jquery I have this:
$(this).click(function(e){
e.preventDefault();
... other stuff...
I do some extra validation stuff and then I submit a form.
I need this
e.preventDefault();
to wait with the submit until I did my extra data validation as well as I use bootstrap sweet alerts to do some other checks as well.
But using this, prevents the standard browser validation for fields with required="required" tags. Which is an "visual" pitty.
Is there a way to prevent in jquery the submission and not destroying the browsers validation?
I'm surprised to find that the form's checkValidity method doesn't do this (it does other things, such as making the browser do its validity checks and set state accordingly).
Some browsers (including Chrome and Firefox) support reportValidity, which does what they do on submit, so you could detect whether that's supported and use it if so:
E.g.:
$(this).click(function(e) {
e.preventDefault();
if (this.form.reportValidity) { // <===
this.form.checkValidity(); // <===
} // <===
// ...
});
...if I assume that what you're clicking is within the form and thus has the form property referring to the form it's in; if not, replace this.form with code that finds the form, e.g.:
var form = $("selector-for-the-form")[0]; // Note getting the raw element
if (form.reportValidity) {
form.reportValidity();
}
Example (live copy on jsFiddle) (I'm not using Stack Snippets because they don't allow even cancelled form submissions and the code didn't work correctly on Firefox in a Stack Snippet; it does work with a cancelled form submission on jsFiddle):
HTML:
<p>Click the button without filling in the field:</p>
<form>
<label>
Required field:
<input type="text" required>
</label>
<input type="submit" id="btn" value="Click to validate">
</form>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
JavaScript:
$("#btn").on("click", function(e) {
e.preventDefault();
this.form.reportValidity();
});
use the submit event instead of click
$(this).on('submit', function(e){
e.preventDefault();
... other stuff...
Not very clear what the problem is but as far as I can understand you can:
set a flag when you have finished checking your validations
instead of preventing the default behaviour check the set flag in
your click function
Imagine this :
<form id="form">
<input type="text">
<button type="submit" name="submit1" value="1">something1</button>
<button type="submit" name="submit2" value="2">something2</button>
<button type="submit" name="submit3" value="3">something3</button>
</form>
First of all when I write $('#form').submit() which submit value will be sent? the first one?
Second of all How can I submit the form without the click trigger event with the value I want? Is it possible at all? For example submitting the form with the 2 submit value.
The reason I want do this is to have confirmation popup with sweetalert before sending my form so here it is :
$('form').on('submit',function(e){
form = $(this);
e.preventDefault();
swal({'some dialog'},function(isConfirm)
{
if(isConfirm)
form.submit;
\\If I use the click trigger I will get stuck in here again.
})
});
There is an alternative - use the FormData You can create an instance of a FormData, add your html form, modify entries, and send it. Everything is under your control here then.
EDIT: Based on your edit, it seems you have the problem of resubmitting the form. You can handle it like this.
var form = document.querySelector('form');
form.addEventListener('submit', {
confirmed: false,
handleEvent: function (event) {
if (this.confirmed)
return;
event.preventDefault();
doconfirm((confirmed) => {
if (confirmed) {
this.confirmed = true;
form.submit();
}
})
}
}, false);
Or you can solve your problem by unbinding the submit handlers after validation and submit it again: $('form').off('submit').submit()
As #Scott Marcus explained, the value of named buttons will be submitted when the form is sent to the server. However in your case, this won't help because you want to perform some logic before submitting it to the server.
The issue is that jQuery has no way to determine which button was clicked because it doesn't provide the submit button values when you look at the form data via $.serialize(), and there is no easy cross-browser friendly way to check the button that triggered the $.submit() event without using click.
So, the only workaround would be to handle the click event of the 3 buttons and store some value that is checked before you submit the form as described in this answer: How can I get the button that caused the submit from the form submit event?
Example: http://codeply.com/go/Wj85swRyfX
Let's take your questions one at a time...
First of all when I write $('#form').submit() which submit value will
be sent? the first one?
When a form is submitted, ALL form elements that nave a NAME attribute will submit their value (even if the value is an empty string) to the form's ACTION destination. So, in your case, all 3 of your buttons have a name attribute and so all 3 buttons will submit their name/value pairs.
Usually, we don't put a name attribute on the submit button because we only want it to trigger the submit, not actually use it as a data container. And, we usually include only a single submit button under most circumstances.
Second of all How can I submit the form without the click trigger
event with the value I want? Is it possible at all? For example
submitting the form with the 2 submit value
You would use:
$('#form').submit()
to manually cause the submit, but you'd need to have an if() statement that has logic that determines which value is appropriate to submit. Instead of the value being stored in a button, you could use a hidden form field, like this:
<form id="form">
<input type="text">
<input type="hidden" name="hidden" value="">
<button type="submit">something3</button>
</form>
JavaScript:
$("#form").on("submit", function(evt){
// Stop the form submission process
evt.preventDefault();
// Logic that sets hidden input field to correct value:
if(condition1){
$("input[type=hidden]").attr("value", "1");
} else if(condition2) {
$("input[type=hidden]").attr("value","2");
} else {
$("input[type=hidden]").attr("value","3");
}
// Manually submit the form
$("#form").submit();
});
I suggest to use hidden input tag to make the logic clear.
I noticed one pecular thing. When there are several submit buttons in your HTML form like so:
<button type="submit" name="submit_button", value="b1"></button>
<button type="submit" name="submit_button", value="b2"></button>
<button type="submit" name="submit_button", value="b2"></button>
..and you do this:
var $form = $('#my_html_form');
$form.submit(function() {
if (!checkPassed && !hasRequiredValue) {
bootbox.confirm('Are you sure that you don\'t need <strong>{requiredValue}</strong> parameter?', function(result) {
if (result) {
checkPassed = true;
$form.submit();
}
});
return false;
}
});
the field submit_button does not get submitted at all, it's just not present in the request data.
Would there be a way to force JS to submit data together with the value of the submit button clicked?
I will only add that if the form is submited with PHP and not JS, the submit_button field is present and has the value of b1, b2, or b3 - depending on which button was clicked.
P.S. I just thought that the source of the problem might be that I'm using <button> instead of <input>. However, as I said, it's all good with PHP.
Only a successful submit button will be included in the form data.
A successful submit button is one that is used to submit the form.
Your JavaScript runs on the submit event and:
Always cancels the submission of the form
Sometimes submits the form with JS
Since you are submitting the form with JS instead of the submit button, none of the submit buttons are successful.
Change your JS so that it:
Sometimes cancels the submission of the form
Such:
$form.submit(function() {
// Add a NOT condition here
if (!<someCondition>) {
return false;
}
return true;
});
Regarding the update:
OK, so you are always canceling the submission, and using a DOM based widget to ask for confirmation.
In that case, you need to capture the value of the submit button separately.
The information isn't exposed to the submit event so you need to do it on the click event of the submit button.
Add a hidden input to your form:
<input type="hidden" name="submit_button">
Then add another event handler:
$form.on("click", '[name="submit_button"]', function (event) {
$form.find('[type="hidden"][name="submit_button"]').val(
$(this).val()
);
});
Yes you can get the value of the button
$('button').click(function(event) {
var button = $(this).data('clicked', $(event.target));
var value = button.val();
});
Here you go.
$("button[name=submit_button]").click(function() {
alert($(this).val());
});
Fiddle: http://jsfiddle.net/tw698hvs/
**Update: I have pasted working code in order to erase any ambiguity about what is going on. I have also tried to remove the preventDefault on both handlers, does not help*
I have a form where upon the button click, a JS event needs to happen, and the form needs to submit.
As per the code below, what I thought would happen is: alert(button), then alert(form), or vice versa. I do not care about sequence.
If i run it however, the alert(button) will show up, but the alert(form) will not.
If i comment out the code for the button, the form alert comes up.
Do i have some fundamental misunderstanding of how this is supposed to work?
jQuery(document).ready(function(){
$("form.example").submit(function(event){
event.preventDefault();
alert("form submitted");
});
$("form.example button").click(function(event){
event.preventDefault();
alert("button clicked");
});
)};
<form class="example" action="/v4test">
<button type="submit">Meow!</button>
</form>
After edit of OP
You do not need to preventDefault of the click.... only the submit... here is you working code:
jsFiddle example
jQuery(document).ready(function(){
$('form.example').submit(function(event){
event.preventDefault();
alert("form submitted");
// stop submission so we don't leave this page
});
$('form.example button').click(function() {
alert("button clicked");
});
});
old answer
You can simply put your .click() and .submit() handlers in series, and they should not cancel out. You have some syntax errors in your pseudo code.... maybe those are causing problems?
Another potential problem is that $("form button") targets the HTML <button> tags. If you use <input type="button" /> you should use $("form:button") and note that <input type="submit" /> is not a button. Anyway, I'll assume you are in fact using the <button> tags.
Usually return false is used inside .submit(function() { ... });. This stops the form from being submited through HTML. s**[topPropagation][6]** is very different. It deals with stopping events "bubbling up" to the parents of elements....... But I don't see how this would effect your case.
If you are doing a true HTML submission, make sure to put your .click() handler first, since a true HTML submission will cause you to leave the page.
If you use return false inside .submit(), the form will not be submitted through the HTML, and you'll have to handle the submission with jQuery / Javascript / AJAX.
Anyway, here is a demonstration of both the .click() and .submit() events firing in series... the code is below:
jsFiddle Example
$(function() {
$('form button').click(function() {
// Do click button stuff here.
});
$('form').submit(function(){
// Do for submission stuff here
// ...
// stop submission so we don't leave this page
// Leave this line out, if you do want to leave
// the page and submit the form, but then the results of your
// click event will probably be hard for the user to see.
return false;
});
});
The above will trigger both handlers with the following HTML:
<button type="submit">Submit</button>
As a note, I suppose you were using pseudo code, but even then, it's much easier to read, and one is sure you're not writing syntax errors, if you use:
$('form').submit(function() { /*submits form*/ });
$('form button').click(function() { /*does some action*/ });
If you put a return false on the click, it should cancel the default behavior. If you want to execute one then the other, call $('form').submit() within the click function. e.g.
$('form').submit { //submits form}
$('form button').click {
// does some action
$('form').submit();
}
There seems to be a bit of confusion about propagation here. Event propagation (which can be disabled by stopPropagation) means that events "bubble up" to parent elements; in this case, the click event would register on the form, because it is a parent of the submit button. But of course the submit handler on the form will not catch the click event.
What you are interested in is the default action, which in the case of clicking a submit button is to submit the form. The default action can be prevented by either calling preventDefault or returning false. You are probably doing the latter.
Note that in Javascript functions which do not end with an explicit return do still return a value, which is the result of the last command in the function. You should end your click handler with return; or return true;. I have no idea where I got that from. Javascript functions actually return undefined when there is no explicit return statement.
Does clicking the button submit the form? If so:
// Disable the submit action
$("form").submit(function(){
return false;
});
$("form button").click(function(){
// Do some action here
$("form").unbind("submit").submit();
});
If you don't unbind the submit event when you click the button, the submit will just do nothing.