I'm facing a sort of dummy problem.
On my site there is an order form (simple html form) and I noticed that I get double commands from time to time.
I realized that if I clicked repeatedly few times the submit button (before the action page is loaded) I got as many commands as I have clicked.
So I wonder if there are simple solution to make form submission asyncronous?
Thanks
P.S. I added JQuery UI dialog on submit "wait please..." but I get still double commands.
UPDATE
As GeoffAtkins proposed I will:
disable submit after dialog is shown
make use of unique form's token (as it is already added by Symfony) Do not use Symfony token as unique form token as it is always the same for current session. Use just random or something like that.
I would consider doing this (jQuery since you said you used that)
$(function() {
$("#formId").on("submit",function() {
$("#submitBut").hide();
$("#pleaseWait").show();
});
});
if you submit the form and reload the page.
If you Ajax the order, then do
$(function() {
$("#formId").on("submit",function(e) {
e.preventDefault();
var $theForm = $(this);
$("#submitBut").hide();
$("#pleaseWait").show();
$.post($(this).attr("action"),$(this).serialize(),function() {
$theForm.reset();
$("#submitBut").show(); // assuming you want the user to order more stuff
$("#pleaseWait").hide();
});
});
});
NOTE that disabling the submit button on click of the submit button may stop the submission all together (at least in Chrome): https://jsfiddle.net/mplungjan/xc6uc46m/
Just disable the button on click, something like:
$("#my-button-id").on("click", function() {
$(this).attr("disabled", "disabled");
});
var bool = true;
function onclick()
{
if(bool)
{
//do stuff
bool = false;
}
else
{
//ignore
}
}
You could disable the button on the form when it is clicked, and then continue to perform the action. You would probably change the text to say "loading..." or some such.
You may also want to re-enable the button on fail or complete of the ajax request.
I've done this many times similar to this: https://stackoverflow.com/a/19220576/89211
Related
I have a jquery bug that I cant solve - hoping for help with a solution. Dont know if it is browser bug related (probably not), jQuery related, or Yii (our backend) related - but I need to try to solve it with the jQuery portion. Code at bottom of message.
Requirement: Disable accidental double submissions on forms.
Current Solution: Check for form submission state through a delegate and when the DOM form state changes to submit - append the disable attribute to the form submit button to prevent accident double form submission.
jQuery double click disabler:
$( document ).ready(function() {
$('html').delegate('form', 'submit', function() {
$(this).find(':submit').attr('disabled', true);
});
});
Problem: This works perfectly on every part of the CRM we are developing EXCEPT for a single timekeeper (clock in/clock out) feature. With the timekeeper the form has two submit buttons (one for clock in, one for clock out). Only one submit button shows at a time (Either "In" or "Out". When you click the button - it submits the form and changes the submit button to the other state by checking a session var to determine what state it is in and determines which of the two submit buttons are to be displayed. Problem is if you click it, the form appears to submit, but the state don't change. If you click it really fast a few times you can get it to change state. I suspect this is a timing or order of operations issue, but I have no idea how to fix it. The fix MUST be done on the front end, so here is the code (both the PHP being impacted and jQuery double click prevention). Perhaps a different method of disabling double submissions may work, please post your solution if you have one to try. Commenting out the current jQuery allows the form to function as designed. What might be causing this, and how might I change the jQuery double click prevention to solve it?
On page PHP for the time clock:
<form action = "<?=$clockUrl?>" method = "post" >
<input type = "hidden" name = "previousUrl" value = "<?=$currentUrl?>">
<?php if ($sessionVar->timeclockin) {?>
<input type = "submit" name = "submit-clockout" value = "Out">
<class="clock-time" ><?=$sessionVar->timeclockin?></class="clock-time">
<?php } else {?>
<input type = "submit" name = "submit-clockin" value = "In">
<?php }?>
</form>
Thank you for pointing me in the right direction Tyler! I was able to fix the issue with the following alteration to my script.
function do_nothing() {
console.log("click prevented");
return false;
}
$('html').delegate('form', 'submit', function(e) {
$(e.target).find(':submit').click(do_nothing);
setTimeout(function(){
$(e.target).unbind('click', do_nothing);
}, 10000);
});
Update 1:
If you are looking to prevent the button from being pressed twice then inside of your onclick or submit function, you should use something similar to the following:
$('#yourButton').prop('disabled', true);
If the page then redirects then you won't have to undo this. If it does, then do the opposite by changing true to false.
The submit function should instead disable the submit button until it either returns or fails.
An alternative is to use a lambda style function and replace it temporarily with an empty function until the request returns or fails.
I have a form that uploads a file and targets an iframe on the page. When the user clicks submit, I want the file contents to "clear" out.
I tried this
$('#imageaddform').submit(function(){
$('#imagefile').val('');
});
But it clears the form before the submit, so nothing is ever uploaded.
Is how do I clear after submit?
If you have no other handlers bound, you could do something like this:
$('#imageaddform').submit(function(e) {
e.preventDefault(); // don't submit multiple times
this.submit(); // use the native submit method of the form element
$('#imagefile').val(''); // blank the input
});
Lonesomeday's solution worked for me but for Google Chrome I found it would still submit empty form data unless I added a timeout like this:
$('#imageaddform').submit(function(e) {
e.preventDefault(); // don't submit multiple times
this.submit(); // use the native submit method of the form element
setTimeout(function(){ // Delay for Chrome
$('#imagefile').val(''); // blank the input
}, 100);
});
You could do something like this:
$('#imageaddform').submit(function(){
setTimeout(function() {
$('#imagefile').val('');
},100);
});
How are u submitting the form? if this is normal form post then then page wont exist in that case i am wondering if u are looking to clear the form before the page refreshses so that when the user comes back he doesn't see the values populated.
If the form is submitted by ajax then you can
function(){
$('form1')[0].submit();
clearForm();
}
Did i miss the question?
For now it seems to work without problems but I was wondering...Let's say you have multiple forms (each on a different page) with each and one of them a different id.
Each form has a button with and id "btnSave". In the masterpage (template) I added all links to the ajax-formhandling-scripts working like this:
$(document).ready(function() {
// ignore the submit
$("#frmNews").submit(function() {
return false;
});
// catch the click-event
$("#btnSave").on("click", function() {
// input control
// ajax-request if input was ok
}
});
Before I continue to build I want to know sure using the same button-id won't give me problems. Am I working wrong here?
Repeated id attribute values are invalid - they must be unique. Use a class instead. Also, from a design point of view you should hang all logic off the submit event of the form. Try something like this:
$(document).ready(function() {
// ignore the submit
$(".frmNews").submit(function(e) {
// input control
if (input_control_ok) {
// $.ajax()...
}
else {
e.preventDefault(); // stop form submission
}
});
});
The .btnSave button should then have the type="submit" attribute added to it, assuming it doesn't already.
I want to prevent multiple form submissions, but I need to have the value of the submit element posted back to the server (so that I know which button the user clicked on).
Most of the Internet Wisdom concerning suppression of multiple form submissions seems to involve disabling the submit button during form submission. This prevents the button from being clicked a second time, but also prevents its value from being posted.
I've found a few examples of JS code that hides the submit button(s), which allows their values to be posted. But those examples all replace the (now hidden) button with some sort of "processing..." message. I really want a solution that presents the user with a disabled button but still posts the button value.
I should add that I'd prefer a solution that works with standard HTML one would find in most forms. No magic IFrames, hidden fields, id or class names, etc. I want a JS function I can stash away in a library and reference from all of my existing forms to enable this new behavior.
(I have a solution, which I will post as an answer. But I had to ask the question to comply with the Zen of SO.)
Here is (yet another) answer to the question of how to deal with preventing the user from clicking on the form submission button more than once. This solution makes it appear that the button has been disabled.
Under the covers, it creates a disabled button to display to the user, and hides the actual button so that its value is posted. I also move the hidden button so that the extra element doesn't mess up CSS selectors.
Also note the check for invalid form fields. If you omit this check, and form validation fails, then the user winds up with a form that wasn't posted (because client-side validation failed) but the buttons are disabled.
// Disables buttons when form is submitted
$('form').submit(function () {
// Bail out if the form contains validation errors
if ($.validator && !$(this).valid()) return;
var form = $(this);
$(this).find('input[type="submit"], button[type="submit"]').each(function (index) {
// Create a disabled clone of the submit button
$(this).clone(false).removeAttr('id').prop('disabled', true).insertBefore($(this));
// Hide the actual submit button and move it to the beginning of the form
$(this).hide();
form.prepend($(this));
});
});
Because you can submit a form other ways than simply clicking the submit button it's better to add a listener to the form's submit event rather than the click event on the submit button. This jQuery event listener should work on any form and prevent it from being submitted more than once.
$('form').on('submit', function(e) {
if (!$(this).data('submitted')) {
$(this).data('submitted', true);
}
else {
e.preventDefault();
}
});
To make the form look disabled you could add some css that makes the form look disabled and then add the classname on form submission.
$('form').on('submit', function(e) {
if (!$(this).data('submitted')) {
$(this).data('submitted', true).addClass('disabled');
}
else {
e.preventDefault();
}
});
I wanted to stop the user from causing multiple form submissions by double clicking the submit button or hitting the enter key twice. I like this solution, because it doesn't require a hidden form field or hiding the submit button.
The two key points are:
Return true/false instead of using e.preventDefault() and form.submit(), because form.submit() doesn't know which button was clicked and therefore, can't pass the button name/value.
Disable the button with pointer-events: none; instead of disabled="disabled", because the disabled attribute won't send the button name/value. I believe pointer-events: none; is not supported by Internet Explorer 10 or below.
javascript/jquery code:
var form_selector = 'form',
button_selector = 'button, input[type=submit], input[type=button], input[type=reset]',
deactivated_classname = 'state-submitting',
deactivated_class = '.'+'state-submitting';
// Capture the submit event so it will handle both the
// enter key and clicking the submit button.
$(document).on('submit', form_selector, function(e) {
var form = e.target,
buttons = $( form ).find( button_selector );
// Returns, because the form is already being submitted by a previous attempt.
if( $( form ).find( deactivated_class ).length > 0 ) return false;
disableButtons( buttons );
// Safari (version 11) bugfix: Safari needs a timeout or it won't
// show the deactivated styles.
setTimeout(function() {
// Must use return true, because using form.submit(), won't pass the button value.
return true;
}, 50 );
});
function disableButtons( buttons ) {
// Disables all buttons in the form.
$( buttons ).each(function( index, elem ) {
$( elem ).addClass( deactivated_classname );
});
}
For AJAX forms, you will want to re-enable the buttons after the response is returned.
$( document ).on( 'ajax:complete', form_selector, function(e) {
var form = e.target,
buttons = $( form ).find( button_selector );
enableButtons( buttons );
});
function enableButtons( buttons ) {
$( buttons ).each(function( index, elem ) {
$( elem ).removeClass( deactivated_classname );
});
}
CSS:
// The button is disabled while it is submitting.
.state-submitting {
// Turns off hover and click events. Not supported in IE 10 and below.
pointer-events: none;
opacity: 0.5;
}
You can simulate disabled look behavior. E.g. if you have a button like this:
<input id="btn" type="button" onclick="disableMe(this)" value="Submit" />
You can define CSS like this
.disabled {
backround-color:grey;
color:darkgrey;
}
And JS like this
function disableMe(btn) {
btn.className = "disabled";
btn.onclick = function(){return false}
}
What will happen - on first click button will become grey (via applied CSS) and onclick event will change to "return false" for all the consecutive calls preventing future click actions. The button will appear and act as disabled, but will not be, so it will not prevent button submission.
Here's a couple options:
1. You could create hidden inputs and dynamically change the value of it before the form is submitted either onClick or onHover of the said button:
2. You could create an hidden iframe which is the target of the said form. Once the submit button is click, you could cancel the submit event, grab all of the data and send it programatically through the iframe instead.
I was having the same issue as OP, and I found that disabling the submit button(s) after a short (maybe 0 seconds) timeout via setTimeout does the trick. The submit button's name value is still posted with the rest of the form data as desired, but the button disables itself (almost) immediately, preventing further clicks.
The timeout is a bit ugly, but it seems preferable to more elaborate swapping/covering schemes.
This could be combined with also altering the form's onsubmit property for extra precaution, but I'm not doing that in the example below for clarity's sake. Either way, I like the appearance/behavior of a disabled button after the first submission click… the user experience seems better to me… it's more clear what's happening.
My form element's start tag:
<form onsubmit="return formSubmit(this);" method="post" action="">
In my JavaScript (sorry, I'm not up-to-date with the latest JS tech like jQuery, etc, so I'm posting this in old-fashioned-native-JavaScript-5-with-no-dependencies-compatible code):
function formSubmit(form) {
// MUST DELAY so as not to break input/button[type=submit] name submission
setTimeout(function () {
var els = form.elements;
for (var i = 0; i < els.length; i++) {
var el = els[i];
if (el.getAttribute('type') == 'submit') {
el.setAttribute('disabled', 'disabled');
}
}
}, 0);
return true;
}
I think better solution would be to use JQuery :
<form onsubmit="$('#submit').hide();" method="post" action="">
No chance of double clicking.
Sometimes we use name field in submit button for validation so if this is disabled then that could failed.
Using .hide() the button will be hidden.
so no chance of double clicking it.
Be honest with you I was not able to understand fully most of the posts on this page, but I think I have faced this problem before, and solved it by allowing the page to post the first time the button is clicked, so when the page comes back from server it has the new value assigned to it, and it looks clickable, and enabled. But if a 2nd attempt is made to press it, then it becomes disabled, and page will not post, and send to the server again by clicking this button. I hope this helps:
#section scripts
{
<script type="text/javascript">
$('#edit').click(function () {
if (document.getElementById("edit").value == '') {
// This portion should execute onlythe
// first time button is clicked, and it
// will assign a new value to the button,
//and posts the value
//to the server
}
else {
edit.disabled = true;
}
});
</script>
}
A much much much simpler way is to enclose whatever code you use to disable the button in a setTimeout() with 0 delay. That way the button is still enabled in the thread that handles the form submission while another parallel thread is spawned to do the disabling.
Example (using jQuery):
<form method="POST" onsubmit="javascript:setTimeout(() => $('*[type=submit]', this).attr('disabled', 'disabled'), 0)">
I have following jQuery code to prevent double clicking a button. It works fine. I am using Page_ClientValidate() to ensure that the double click is prevented only if the page is valid. [If there are validation errors the flag should not be set as there is no postback to server started]
Is there a better method to prevent the second click on the button before the page loads back?
Can we set the flag isOperationInProgress = yesIndicator only if the page is causing a postback to server? Is there a suitable event for it that will be called before the user can click on the button for the second time?
Note: I am looking for a solution that won't require any new API
Note: This question is not a duplicate. Here I am trying to avoid the use of Page_ClientValidate(). Also I am looking for an event where I can move the code so that I need not use Page_ClientValidate()
Note: No ajax involved in my scenario. The ASP.Net form will be submitted to server synchronously. The button click event in javascript is only for preventing double click. The form submission is synchronous using ASP.Net.
Present Code
$(document).ready(function () {
var noIndicator = 'No';
var yesIndicator = 'Yes';
var isOperationInProgress = 'No';
$('.applicationButton').click(function (e) {
// Prevent button from double click
var isPageValid = Page_ClientValidate();
if (isPageValid) {
if (isOperationInProgress == noIndicator) {
isOperationInProgress = yesIndicator;
} else {
e.preventDefault();
}
}
});
});
References:
Validator causes improper behavior for double click check
Whether to use Page_IsValid or Page_ClientValidate() (for Client Side Events)
Note by #Peter Ivan in the above references:
calling Page_ClientValidate() repeatedly may cause the page to be too obtrusive (multiple alerts etc.).
I found this solution that is simple and worked for me:
<form ...>
<input ...>
<button ... onclick="this.disabled=true;this.value='Submitting...'; this.form.submit();">
</form>
This solution was found in:
Original solution
JS provides an easy solution by using the event properties:
$('selector').click(function(event) {
if(!event.detail || event.detail == 1){//activate on first click only to avoid hiding again on multiple clicks
// code here. // It will execute only once on multiple clicks
}
});
disable the button on click, enable it after the operation completes
$(document).ready(function () {
$("#btn").on("click", function() {
$(this).attr("disabled", "disabled");
doWork(); //this method contains your logic
});
});
function doWork() {
alert("doing work");
//actually this function will do something and when processing is done the button is enabled by removing the 'disabled' attribute
//I use setTimeout so you can see the button can only be clicked once, and can't be clicked again while work is being done
setTimeout('$("#btn").removeAttr("disabled")', 1500);
}
working example
I modified the solution by #Kalyani and so far it's been working beautifully!
$('selector').click(function(event) {
if(!event.detail || event.detail == 1){ return true; }
else { return false; }
});
Disable pointer events in the first line of your callback, and then resume them on the last line.
element.on('click', function() {
element.css('pointer-events', 'none');
//do all of your stuff
element.css('pointer-events', 'auto');
};
After hours of searching i fixed it in this way:
old_timestamp = null;
$('#productivity_table').on('click', function(event) {
// code executed at first load
// not working if you press too many clicks, it waits 1 second
if(old_timestamp == null || old_timestamp + 1000 < event.timeStamp)
{
// write the code / slide / fade / whatever
old_timestamp = event.timeStamp;
}
});
you can use jQuery's [one][1] :
.one( events [, data ], handler ) Returns: jQuery
Description: Attach a handler to an event for the elements. The handler is executed at most once per element per event type.
see examples:
using jQuery: https://codepen.io/loicjaouen/pen/RwweLVx
// add an even listener that will run only once
$("#click_here_button").one("click", once_callback);
using count,
clickcount++;
if (clickcount == 1) {}
After coming back again clickcount set to zero.
May be this will help and give the desired functionality :
$('#disable').on('click', function(){
$('#disable').attr("disabled", true);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="disable">Disable Me!</button>
<p>Hello</p>
We can use on and off click for preventing Multiple clicks. i tried it to my application and it's working as expected.
$(document).ready(function () {
$("#disable").on('click', function () {
$(this).off('click');
// enter code here
});
})
This should work for you:
$(document).ready(function () {
$('.applicationButton').click(function (e) {
var btn = $(this),
isPageValid = Page_ClientValidate(); // cache state of page validation
if (!isPageValid) {
// page isn't valid, block form submission
e.preventDefault();
}
// disable the button only if the page is valid.
// when the postback returns, the button will be re-enabled by default
btn.prop('disabled', isPageValid);
return isPageValid;
});
});
Please note that you should also take steps server-side to prevent double-posts as not every visitor to your site will be polite enough to visit it with a browser (let alone a JavaScript-enabled browser).
The absolute best way I've found is to immediately disable the button when clicked:
$('#myButton').click(function() {
$('#myButton').prop('disabled', true);
});
And re-enable it when needed, for example:
validation failed
error while processing the form data by the server, then after an error response using jQuery
Another way to avoid a quick double-click is to use the native JavaScript function ondblclick, but in this case it doesn't work if the submit form works through jQuery.
One way you do this is set a counter and if number exceeds the certain number return false.
easy as this.
var mybutton_counter=0;
$("#mybutton").on('click', function(e){
if (mybutton_counter>0){return false;} //you can set the number to any
//your call
mybutton_counter++; //incremental
});
make sure, if statement is on top of your call.
If you are doing a full round-trip post-back, you can just make the button disappear. If there are validation errors, the button will be visible again upon reload of the page.
First set add a style to your button:
<h:commandButton id="SaveBtn" value="Save"
styleClass="hideOnClick"
actionListener="#{someBean.saveAction()}"/>
Then make it hide when clicked.
$(document).ready(function() {
$(".hideOnClick").click(function(e) {
$(e.toElement).hide();
});
});
Just copy paste this code in your script and edit #button1 with your button id and it will resolve your issue.
<script type="text/javascript">
$(document).ready(function(){
$("#button1").submit(function() {
$(this).submit(function() {
return false;
});
return true;
});
});
</script
Plain JavaScript:
Set an attribute to the element being interacted
Remove the attribute after a timeout
If the element has the attribute, do nothing
const throttleInput = document.querySelector('button');
throttleInput.onclick = function() {
if (!throttleInput.hasAttribute('data-prevent-double-click')) {
throttleInput.setAttribute('data-prevent-double-click', true);
throttleInput.setAttribute('disabled', true);
document.body.append("Foo!");
}
setTimeout(function() {
throttleInput.removeAttribute('disabled');
throttleInput.removeAttribute('data-prevent-double-click');
}, 3000);
}
<button>Click to add "Foo"!</button>
We also set the button to .disabled=true. I added the HTML Command input with type hidden to identify if the transaction has been added by the Computer Server to the Database.
Example HTML and PHP Commands:
<button onclick="myAddFunction(<?php echo $value['patient_id'];?>)" id="addButtonId">ADD</button>
<input type="hidden" id="hasPatientInListParam" value="<?php echo $hasPatientInListParamValue;?>">
Example Javascript Command:
function myAddFunction(patientId) {
document.getElementById("addButtonId").disabled=true;
var hasPatientInList = document.getElementById("hasPatientInListParam").value;
if (hasPatientInList) {
alert("Only one (1) patient in each List.");
return;
}
window.location.href = "webAddress/addTransaction/"+patientId; //reloads page
}
After reloading the page, the computer auto-sets the button to .disabled=false. At present, these actions prevent the multiple clicks problem in our case.
I hope these help you too.
Thank you.
One way I found that works is using bootstrap css to display a modal window with a spinner on it. This way nothing in the background can be clicked. Just need to make sure that you hide the modal window again after your long process completes.
so I found a simple solution, hope this helps.
all I had to do was create a counter = 0, and make the function that runs when clicked only runnable if the counter is = 0, when someone clicks the function the first line in the function sets counter = 1 and this will prevent the user from running the function multiple times when the function is done the last line of the code inside the function sets counter to 0 again
you could use a structure like this, it will execute just once:
document.getElementById('buttonID').addEventListener('click', () => {
...Do things...
},{once:true});