Disabling WooCommerce add to cart button after first click prevents submit - javascript

I'm trying to disable the WooCommerce Add to cart button when the user clicks it for two reasons..
To prevent multiple clicks on it
To show the user their click did something
I used this code:
if ($('body').filter('.single-product')) {
var add_cart_button = $('.single_add_to_cart_button');
/* Disable button on add to bag click if button is active */
add_cart_button.on('click', function(e) {
if (!$(this).hasClass('disabled')) {
$(this).prop('disabled', true); // Prevent multi adds
$(this).addClass('disabled');
}
});
}
Whilst this works, it also seems to disable the button even working, the adding of the product doesn't work as the form submit seems to not fire at all.
Why is this happening and what do I need to change here?

Fixed it by doing it with the submit event instead...
Since the form doesn't have a name attribute I had to target it another way:
if ($('body').filter('.single-product')) {
var add_cart_button = $('.single_add_to_cart_button');
add_cart_button.closest('form').on('submit', function(e) {
var cur_atc_button = $(this).find('.single_add_to_cart_button');
if (!cur_atc_button.hasClass('disabled')) {
cur_atc_button.addClass('disabled');
}
});
}
Edit: I removed the below disabling of the button as it seems for some item types it failed to add the item to the cart if you did this:
cur_atc_button.prop('disabled', true); // Prevent multi adds
If anyone knows why please let me know.

Related

Issue in clicking links with window.onbeforeunload

I have a parent div content_div which contain form elements inside a table where user selects multiple row elements(clickable rows),download link elements etc.
I have a warning pop up for the user changes done and then try to refresh without clicking save button.
When I select a row and tried to click a download link inside that row,I dont need to show the warning popup.I have the following code but its not working.
If I dont select any rows and tried to click any download links,its not showing any popup,means thats fine.
If I select any rows and then try to click any download links,its showing me the popup which is wrong in my case.
If a user clicks on some other links outside my #content_div,its showing the popup which is true for me.
$(function() {
var formmodified = 0;
//click event for each row inside the table
$(".course_row").click(function(e) {
-- -- -
formmodified = 1; //setting the variable to 1 means user
has changed something inside the page
});
//when form submits
$("#submit").click(function() {
formmodified = 0; //assuming that form is saved after form change
});
//function for warning popup
window.onbeforeunload = confirmExit;
function confirmExit() {
var element_clicked = 0;
//#content_div is the main parent which contain the entire
contents.
$('#content_div').children().on('click', function(e) {
console.log('clicked');
element_clicked = 1; //means the clicked element is inside the #content_div which can be a link or other things
});
console.log(element_clicked);
EDIT: I am always getting element_clicked value as 0 when I click any element inside the div.The value 'clicked'
is showing.I dont know why the value
for the variable is not setting to 1
if (element_clicked) {
//element_clicked = false;
return; // abort beforeunload
} else {
if ((!element_clicked) && (formmodified == 1)) {
return "The selected courses are not saved.
Do you wish to leave the page ? ";
}
}
}
});
Please help me in this case.Thanks in advance
Just add click() event to anchor elements and unbind onbeforeunload event.
$("a").on('click', function() {
window.onbeforeunload = null;
});
This is just an example. You can add a class or id to the selector so that the event is unbinded only when clicked on a specific anchor tag.
For example
$("#content_div a").on('click', function() {
window.onbeforeunload = null;
});
EDIT
If you want to add onbeforeunload to refresh, you either have to do it when any change is trriggered ir just add event when F5 button is pressed.
To be honest I think that first solution is better, necause then even if user clicks refresh button in a browser the popup will come out.
So you would have to change your functionality.
If you do not want to. Here is a quick add to F5 button.
$(document.body).on("keydown", this, function (event) {
if (event.keyCode == 116) {
window.onbeforeunload = true;
}
});

jQuery - Bind click to specific Ajax content element

I have this form that loads using jQuery $.ajax another form inside a container.
The list:
The loaded content within the container called form_load_dropdown_content:
On the left I have two small icons for edit and add. I want to use another ajax call to run specific PHP scripts to carry on the action desired.
I have the following problem:
when I click on each icon submit and respectively reset buttons display
when I click on the reset the both submit and reset are set to display: none
when I click on any the icon again, the click remains bind to the previous icon clicked before.
This is what I am doing:
form_load_dropdown_content.on("click", ".icon", function() {
// reusable selectors
var icon_box = $(".box_edit_icons");
var button_box = $(".box_buttons");
var submit_btn = $(".box_buttons input[type='submit']");
var reset_btn = $(".box_buttons input[type='reset']");
var option_value_input = $("input.option_value");
var option_order_input = $("input.option_order");
// common functions
button_box.show();
icon_box.hide();
if($(this).hasClass("ico_edit_small"))
{
// editing
form_load_dropdown_content.on("click", "input[type='reset']", function(event){
alert("reset from edit");
button_box.hide();
icon_box.show();
});
}
else if($(this).hasClass("ico_add_small"))
{
// adding
form_load_dropdown_content.on("click", "input[type='reset']", function(event){
alert("reset from add");
button_box.hide();
icon_box.show();
});
}
How can I differentiate between the two clicks, so that when I display the submit and reset from a specific icon type to run differentiated actions?
More clear:
when I click icon_add_small and then reset => output: 'reset from add'
then when I click icon_edit_small and then reset => output: 'reset from edit'... and so on without mixing the clicks.
I truly appreciate any help. I tried everything regarding stopping the propagation of the click... but nothing worked.
-----------------------------------------------------------
Edit:
I changed the if part to the following code and it works. Should I expect any problems for unbinding the click?
if($(this).hasClass("ico_edit_small"))
{
// editing
reset_btn.off("click");
reset_btn.click(function(event){
alert("reset from edit");
button_box.hide();
icon_box.show();
});
}
else if($(this).hasClass("ico_add_small"))
{
// adding
reset_btn.off("click");
reset_btn.click(function(event){
alert("reset from add");
button_box.hide();
icon_box.show();
});
}

Disable button until one radio button is clicked

So I'm busy on a registration, and I want people to choose their gender. I do this by the use of radio buttons. Now, what I want, is to have a disabled post button untill one of the two boxes is selected, this I do with jQuery:
var $radio = $("input:radio");
$radio.change(function()
{
var checkedButtons = false;
$radio.each(function() {
if (this.checked)
{
var checkedButtons = true;
return false;
}
});
if (checkedButtons)
{
$("#postGender").removeAttr("disabled");
}
else
{
$("#postGender").attr("disabled", "disabled");
}
});
This little piece is code, was found by me on stackoverflow. The only thing wrong is that it doesn't work.
See this for more code and ofcouse a demo: JsFiddle
You could reduce all that to one line:
$("input:radio").change(function () {$("#postGender").prop("disabled", false);});
jsFiddle example
Remove the var within the first if block. var checkedButtons = true; is creating a different checkedButtons within the scope of that block. So the first checkedButtons will be unchanged, and the other is gone once the if block is finished.
It should just be checkedButtons = true;
You can simplify this greatly.
If you think about it, once they click on a radio button, they can't really deselect it: they can only click on another radio button. So, once the button has changed once, there's really no need to monitor it anymore and you can just enable the button from there.
$("input:radio").change(function () {
$("#postGender").attr("disabled", false);
});
Demo
Something like this should do:
var $radio = $("input:radio");
$radio.change(function () {
if ($radio.filter(':checked').length > 0) {
$("#postGender").removeAttr("disabled");
} else {
$("#postGender").attr("disabled", "disabled");
}
});
http://jsfiddle.net/n6sta3dp/8/
A few sidenotes:
Once a radio button has been checked, it can never be unchecked by the user (unless he starts using the js console). I think it would be safe to remove the 'else' part in your function.
Don't forget that a form can also be submitted by using the enter key, so just disabling the button will not be enough. You should probably listen for the submit event of your form as well and check if the user made a choice before letting the submit go trough.

Disable button on form submission but post button value

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)">

Disable submit button after click to prevent users from sending multiple requests to server

I want to prevent users from clicking on a server button multiple times causing multiple similar requests to be sent to the server.
Buttons are ASP.Net buttons (Webforms). There are many pages on the website and I don't want to write some codes for every button. I want to do it on the Masterpage for all buttons.
A possible solution would be finding the button and disabling it after it has been clicked. like:
$("input[type='submit']").click(function(){
$(this).attr('disabled','disabled');
});
This code works fine but overrides the previous onclick event of the button. So the button doesn't do the submission or any other tasks that it wants to do.
Another solution is disabling all submit buttons on "onbeforesubmit" event. They will be enabled right after the postback. This is also not a good solution because there are some buttons that update part of the page by Ajax and they can not re-enable other buttons beyond the ajax panel after the postback.
Is there a way to find the clicked submit button and disable it and allow it to do it's onclick event?
I found the answer. Because I use asp.net server buttons, Page won't be submitted if I disable the button in client side onclick event. Instead I disable the button in the second click. In this case I can be sure that page has been submitted one time:
$("input[type='submit']").click(function (e) {
if (e.target && Page_IsValid) {
var attr = $(this).attr('submitting');
if (typeof attr !== 'undefined' && attr !== false) { // If button has submitting attribute then do not submit it again.
$(this).prop('disabled', true);
$(this).removeAttr("submitting");
e.preventDefault();
}
else {
$(this).attr("submitting", "true"); // Add "submitting" attribute to prevent multiple submissions.
}
}
});
Try to use .one():
Attach a handler to an event for the elements. The handler is executed
at most once per element per event type.
$("input[type='submit']").one('click',function(){
$(this).prop('disabled',true);
});
Also, you should use .prop() instead of .attr() to set the state of your input
Or what about this?
$("body").on("click", ".js-submit-button", function() {
var $this = $(this);
$this.prop("disabled", true);
$this.closest("form").submit();
});

Categories

Resources