58

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:

  1. Validator causes improper behavior for double click check
  2. 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.).

Community
  • 1
  • 1
LCJ
  • 22,196
  • 67
  • 260
  • 418

20 Answers20

59

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

mauronet
  • 850
  • 12
  • 17
  • 1
    This works very simply and elegantly for a fairly vanilla JSP page with a Java back end that simply refreshes the whole page (forwards to the same JSP) once the work of the submission is done. – Rebeccah Jan 11 '17 at 03:27
  • 15
    If you click fast enough you can still click the button twice – Diego Sep 28 '17 at 15:26
  • 3
    I'm seeing the same thing as Diego, fast enough clicking can still double click it and double submit it. – charley Apr 23 '18 at 20:08
37

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
  }
});
Kalyani
  • 391
  • 3
  • 5
  • @JoseRojas Event.detail is a read-only property which returns the click status -- single, double, or triple click (in the instance of a click listener). While this can be an interesting property in some use-cases, I would not recommend using this method be used for AJAX, or promise-like procedures, where the delay for completion could extend past the timing catch of a triple click which could result in a duplicate action. [Example](https://jsfiddle.net/3yL6hyy8/) – seantunwin Aug 09 '17 at 15:19
  • Nip in the bud solution to avoid multiple clicks. – nagu Sep 25 '18 at 13:16
  • 2
    FYI: event.detail doesn't work in IE11. So, if you are one of the poor souls that are required to maintain that compatibility, like me; good luck! Source: https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/16710370/ – CEPA Feb 21 '19 at 19:25
21

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

Jason
  • 15,915
  • 3
  • 48
  • 72
  • 1
    What if my operation did not complete in 1500ms? The user will be able to click it. I don't think that will work for me. – LCJ May 23 '13 at 13:31
  • 5
    you won't use setTimeout, that was just to show it working. actually you will make your ajax call there, and enable the button by removing the `disabled` attribute when the call is complete in the `done`, `error`, or `always` handler. – Jason May 23 '13 at 13:33
  • So if it errors, just undisable it and let them click it again to retry. – Jacob Morrison May 23 '13 at 13:37
  • see my update to the fiddle, and js code, hopefully that clarifies – Jason May 23 '13 at 13:38
  • No ajax involved in my scenario. The asp.net form will be submitted to server synchronously. I think, this solution won't work for that scenario. – LCJ May 23 '13 at 13:42
  • it will, the doWork method does your validation and then posts the form. the button gets enabled only if page validation fails. – Jason May 23 '13 at 13:43
  • The doWork will be called even if the Asp.Net validation was failed, isn't it? That should not happen. – LCJ May 23 '13 at 13:54
  • the function is irrelevant. the only important thing is to call `attr("disabled", "disabled")` when you want to make the button un-clickable, and `removeAttr("disabled")` to allow button clicking. – Jason May 23 '13 at 13:57
  • 5
    @Jason You should be using `.prop("disabled", true)` (or `false`) to change its disabled state – Ian May 24 '13 at 05:10
12

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; }
});
plaidcorp
  • 625
  • 6
  • 11
  • 3
    Or shorter, `$('selector').click(e => e.detail < 2)`. though in practice I imagine you want to do more than return a boolean. – SamGoody Nov 14 '18 at 12:45
6

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');   
};
Harold
  • 845
  • 1
  • 9
  • 17
  • regarding the downvote, please let me know why this would be a bad idea. i use this now on a few things and would like to change it if this isn't a good idea. thanks much. – Harold May 27 '16 at 11:49
  • 1
    This doesn't stop keyboards which is how many screen readers would be clicking the button. – hostingutilities.com Sep 05 '21 at 02:24
5

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;
    }
    });
Shoyeb Sheikh
  • 2,659
  • 2
  • 10
  • 19
William Laszlo
  • 159
  • 2
  • 4
4

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);
loic.jaouen
  • 489
  • 4
  • 9
  • Looks like `one()` doesn't work for Windows users... – Pathros Sep 07 '20 at 20:51
  • thanks for your interest to my post. That's strange and it should not be related to the OS, eventually to the browser... I don't have a windows machine (therefore no IE) did you try the codepen link above? with which browser? – loic.jaouen Sep 08 '20 at 22:59
  • Testing my application with an end-user using IE, she showed me that right after clicking on the submit button, it was indeed disabled but it wasn't actually submitted. Then I tried using `.on('submit')` instead, then I got it working. – Pathros Sep 10 '20 at 01:28
  • 1
    jQuery's `on()` will keep the event handler active, while `one()` will disable it after the first click. I just tried my codepen on win10/edge and it works, could you make a codepen to showcase your use case? – loic.jaouen Sep 11 '20 at 11:41
2

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>
Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
Rish
  • 1,303
  • 9
  • 22
2

using count,

 clickcount++;
    if (clickcount == 1) {}

After coming back again clickcount set to zero.

Divya
  • 373
  • 4
  • 3
2

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
    });
})
Rohan Kumar
  • 40,431
  • 11
  • 76
  • 106
1

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

pete
  • 24,141
  • 4
  • 37
  • 51
  • Any idea how to do the server-side validation for this in ASP.Net? Any references? – LCJ May 23 '13 at 14:23
  • 1
    It really depends on what you're doing with the form data server-side. For example, if it's just doing a DB insert, you could set your query to disallow inserts of duplicate data (or if you're doing an update you could disallow changes to the same record within 60 seconds, etc.). If you're doing something like a credit-card transaction, then a Post-Redirect-Get (http://en.wikipedia.org/wiki/Post/Redirect/Get) or something similar is a good idea. Ultimately, you need to determine what about the double-posting is bad and take steps to prevent it. – pete May 23 '13 at 14:32
1

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.

user2342558
  • 5,567
  • 5
  • 33
  • 54
0

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.

  • this won't work as the counter isn't incremented, and not decremented. it's also more complicated than required – Jason May 23 '13 at 13:30
  • Here also I need to check `Page_ClientValidate()`. I am trying to avoid the use of `Page_ClientValidate()` – LCJ May 23 '13 at 13:32
0

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();
    });
});
Pixelstix
  • 702
  • 6
  • 21
  • Needing to reload if there are just validation errors is very bad UX - also may not work in some scenarios (you lost information) – Jono Nov 17 '17 at 16:59
  • There are different classifications of validation: a. could be done live in the client (1. as the user types, 2. as they go between fields, or 3. when they hit submit); b. could be done with AJAX; and c. could only be done on the server after the post/submit. If you wanted to go all out, you could make the submit button start out as disabled and only enable it once all of the fields are valid (based on classifications a1, a2, and b). In that case, I'd think making the button disappear after clicking would help prevent double clicking on submit. – Pixelstix Nov 17 '17 at 21:15
0

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
0

Plain JavaScript:

  1. Set an attribute to the element being interacted
  2. Remove the attribute after a timeout
  3. 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>
Lucas Bustamante
  • 15,821
  • 7
  • 92
  • 86
0

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.

masarapmabuhay
  • 466
  • 1
  • 9
  • 15
0

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.

0

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

Ash
  • 21
  • 2
  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Sep 03 '22 at 08:19
0

you could use a structure like this, it will execute just once:

document.getElementById('buttonID').addEventListener('click', () => {
        ...Do things...
 },{once:true});