I'm working on a web project that has a lot of abstraction - lots of code is squirreled away in view templates, internal company javascript libraries, etc.
I have been asked to "hijack" the form submit buttons to disable them when the form is submitted, to disallow extra clicks. The problem is, I still have to submit the button as it's used in 99% of our system as a form input (not best practices, but I didn't write that code!)
What I have done is when the user clicks "Save," that button is hidden using jQuery and an exact duplicate that is disabled with a spinner icon is put in its place:
function showSpinningButton(button){
$(button).hide();
clone = $(button).clone();
clone.prop('disabled', true);
$(button).parent().append(clone);
clone.show();
}
This works in the standard use case, but the niche case is validation - there is no way for me to detect when the form is invalid and the button needs to be reset to standard. This is especially troublesome as all the validation is done in external-facing Javascript libraries that I am not allowed to modify.
The gist is this: is there a DOM event that is fired when a form that had been submitted is cancelled (i.e. onclick="return false;") that I could attach a handler to to reset the button?
You may use a wrapper on the validation function:
var oldHandler = form.prop("onsubmit");
form.removeProp("onsubmit").submit(function(e) {
var result = oldHandler.call(this, e);
if (result == false) {
// reset your button
}
return result;
});
Related
I have an edit form using the jQuery Validation plugin. It's part of an ASP.NET Core project, also using ASP.NET's Unobtrusive Validation plugin. The form has two submit buttons, posting to different handlers server-side:
Submit changes
Delete entry
"Submit changes" is working fine, however I'd like the "Delete" button to skip any client-side validation. Currently it won't post the form if any required fields are missing (or any other validation condition doesn't pass).
I've tried the HTML5 formnovalidate attribute on the "Delete" button without success. Is there an equivalent feature in the jQuery Validation plugin? If not, how would you bypass validation only for a specific submit button?
EDIT:
The "Delete" button is actually outside the <form> tag, but referencing the form by ID through the form attribute:
<form id="my-form">
<!-- form fields and submit button here -->
</form>
<button type="submit" form="my-form" noformvalidate asp-page-handler="Delete">
Delete entry
</button>
I've found that when moving the "Delete" button inside the <form>, the noformvalidate attribute works as expected. I would really like to keep this button outside the <form> tag (due to the page's layout), though I might be able to work around it if there's no other way.
Any ideas on how to make it skip validation while placed outside the form?
The problem you have seems to be summarized in this issue:
Typical save vs submit button where save does not validate and submit
does. Save button is declared with the formnovalidate attrribute. Only
thing is that these buttons are outside of the form itself.
See, the plugin expects the submit buttons to be inside your form. It actually still handles both 'preventing' flags - cancel class and formnovalidate attribute - within click handler propagated from buttons to the top of the form (source):
// "this" is jQuery-wrapped HTMLFormElement with validator attaching
this.on( "click.validate", ":submit", function( event ) {
// Track the used submit button to properly handle scripted
// submits later.
validator.submitButton = event.currentTarget;
// Allow suppressing validation by adding a cancel class to the submit button
if ( $( this ).hasClass( "cancel" ) ) {
validator.cancelSubmit = true;
}
// Allow suppressing validation by adding the html5 formnovalidate attribute to the submit button
if ( $( this ).attr( "formnovalidate" ) !== undefined ) {
validator.cancelSubmit = true;
}
} );
... which clearly doesn't work if buttons are outside of form DOM hierarchy, like in your case. Only submit.validate handler is fired, but it expects to check validator.cancelSubmit flag (and set it to false if it's truthy).
One idea that comes to mind is to place your own click handler on Delete button that will override that flag. Validator instance is accessible through form $.data, as usually with jQuery plugins:
const validator = $.data(form, 'validator');
Perhaps you are looking for something like this:
var $frm = $('#my-form')
, frm = $frm[0]
, $btnsubmit = $('button[type="submit"]');
frm.addEventListener('submit', (evt) => {
var skipValidation = evt.submitter.hasAttribute('formnovalidate')
, validator = $frm.data('validator');
skipValidation && validator !== undefined
? (validator.cancelSubmit = true)
: ($frm.valid() && $btnsubmit.prop('disabled', true));
})
here I'm using a mix of vanilla JS and JQuery because not all submit-event properties are available in JQuery and is not so recommended to access JQuery data using vanilla JS.
In this case, there is no matter where are declared your submit-buttons but... you should be sure to execute the above script before $.validator.unobtrusive.parse(document) that mean before validator.unobtrusive become obtrusive.
I am working on a webpage where a Submit button sumbits a form, but I also want pressing the button to activate a JavaScript function which will disable the Search button and enable a button to reset the search fields and reenable the search button. This is the code currently on the button:
<input id="Search" type="submit" value="Search" onclick="SearchOff()"></input>
And this is the code currently behind that JavaScript function:
function SearchOff() {
document.getElementById("Search").disabled = true;
document.getElementById("Reset_Search").disabled = false;
document.getElementById("[All other relevant fields]").disabled = true;
var x = document.getElementsByTagName("form");
x[0].submit();// Form submission
return true;
}
(I have anonymised the actual function of the application, but it is just entering data into a form which is processed by other JavaScript)
The JavaScript does work, but when onclick="SearchOff()" is in the code, the type=submit function is overridden. Is there any way to get both functions to work? As you can see, I have tried this already with the bottom 2 lines of the JS code, but that was done without onclick="SearchOff()" in the code. I have also tried without this, and had the same problem.
How can I make both functions work at the same time?
Have you tried this idea?
function searchOff(event) {
//No submission yet.
event.preventDefault();
//Disable buttons.
document.querySelector('[type=submit]').disabled = 'disabled';
//Submit the form.
document.querySelector('form').submit();
}
Prevent the form submission when the button is clicked, disable the buttons you need to disable and then, submit the form yourself.
I decided to try retyping the formulas from scratch, which worked onthis occasion for some reason. I think the key was to not copy and paste any of the actual formula, and instead only copy the text to be searched for and counted. This is all I did differently, and I hope reading this helps someone out who reads this.
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
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.
Ok, I am using umbraco forum module, and on the comment form it uses jquery validate plugin.
The problem is that I have added a search button on the same page using a UserControl, the search submit button triggers the comment form submission validation.
I have done some research, and added the 'cancel' css class to the button. This bypass the first validation issue, however, it still fall into the 'submitHandler'. Have read the source code and find a way to detect whether the search button triggers the submission. however, there is not a nice way to bypass the handler.
I am currently using a ugly way to do it: create javascript errors! I would like to know a nicer way to do the job. Many thanks!
Btw, I am currently using:
submitHandler: function (form) {
$(form).find(':hidden').each(function () {
var name = $(this).attr('name');
if (name && name.indexOf('btnSearch') === name.length - 'btnSearch'.length) {
// this is a dirty hack to avoid the validate plugin to work for the button
eval("var error = 1 2 ''");
}
});
// original code from umbraco ignored here....
}
...............
there is similar question here:
jQuery Validation plugin: disable validation for specified submit buttons
(it is a little bit different, as the submitHandler is used in this one...)
Use ignore and set the selector to whatever you need it to be.
$("#myform").validate({
ignore: ".ignore"
})