49

I have an old ASP.NET web forms application (.NET 2.0) that has a process that takes 30 seconds or so to run when a button is clicked. I need to prevent the button from being clicked twice. This will prevent posting twice, which causes duplicate data in a database.

I tried adding;

OnClientClick="this.disabled='true';"

to try to disable the button in JavaScript. However, though the button becomes disabled, the postback for the button then doesn't work.

Disabling the button to prevent multiple submissions is the ideal for this application. How can I do this?

EDIT

I am unable to use third-party controls.

Richard
  • 697
  • 1
  • 7
  • 14

15 Answers15

86

If you simply disable the button then ASP.NET won't post the form. Also you want to deal with client-side validation. Here's my solution:

<asp:Button runat="server" ID="btnSave" 
   Text="Save" OnClick="btnSave_Click" 
   OnClientClick="if (!Page_ClientValidate()){ return false; } this.disabled = true; this.value = 'Saving...';" 
   UseSubmitBehavior="false" />

See @Dave Ward's post for a description of UseSubmitBehavior.

If you have multiple validation groups you'll need to enhance this solution for that.

Rory
  • 40,559
  • 52
  • 175
  • 261
  • 2
    Thanks a lot, this adjustment from another post (I can't find it now) worked for me : OnClientClick=" if (Page_IsValid) {this.value='Saving...';this.disabled=true; }" – user3340627 Mar 19 '15 at 10:05
  • 5
    Removing this part `if (!Page_ClientValidate()){ return false; }` fixed your solution for me. .net 4.5.2 default webform app. – JP Hellemons Jun 15 '16 at 07:51
  • Technically you only need the 'this.disabled=true;'. Everything else is optional – Fandango68 Apr 26 '17 at 02:18
  • Not working if use ***javascript function*** in `OnClientClick` ? – Kiquenet Nov 02 '17 at 10:45
  • Great stuff thank you, was having problems with just disabling the button because of regex validators. – Scath Mar 09 '18 at 16:21
21

You must return true after the OnClientClick:

OnClientClick="this.disabled='true';return true;"

Any clicks in client-side must return true if the postback is to continue, it's a means of providing client-side validatin on button presses.

Mantorok
  • 5,168
  • 2
  • 24
  • 32
  • 26
    That doesn't work. The button is disabled abut the button doesn't cause a postback. – Richard May 26 '11 at 10:41
  • @Richard did you try it? It's not the same as what you posted – Oskar Kjellin May 26 '11 at 10:43
  • I did try it. I copy and pasted the above into a test project, giving: – Richard May 26 '11 at 10:44
  • The code behind the button in the test project is: protected void Button1_Click(object sender, EventArgs e) { Application["count"] = Convert.ToInt32(Application["count"]) + 1; System.Threading.Thread.Sleep(2000); Label1.Text = Application["count"].ToString(); } – Richard May 26 '11 at 10:45
  • That's strange, because I use this with no problems when I've had to, interesting. – Mantorok May 26 '11 at 10:50
  • Try removing the single quotes from the 'true', maybe it's throwing a JS error and not returning true. – Mantorok May 26 '11 at 10:51
  • Or is it this.disabled = 'disabled'...? – Mantorok May 26 '11 at 10:54
  • I tried remove the single quotes. Tried changing to 'disabled' and even disabled, but none worked :( – Richard May 26 '11 at 10:59
  • As a workaround I got the OnClientClick event to call a javascript function that counts the clicks. For one click, it returns true. For anything other than one click it disables the button and returns false. This works but is inelegant. – Richard May 26 '11 at 11:00
  • 2
    – Richard May 26 '11 at 11:00
  • The downside is that the button appears enabled after clicking until you click for a second time. The upside is that the functionality is correct. I reckon I'll get some customer grumbles or the customer will always click twice to see the button disabled. However, that's better than having data duplicated. – Richard May 26 '11 at 11:04
  • 14
    This isn't clearly stated above but I thought I would add if it helps anyone, and could of been the reason OP was having problems.. If you disable a submit button once it is clicked, then it won't postback. – Jordan May 22 '12 at 19:51
  • 5
    As well as not working because ASP.NET doesn't postback if the submit button is disabled, this also doesn't take into account any validation on the page – Rory Aug 06 '12 at 16:01
  • while the form is being submitted, we can disable the respected submit button, ref: https://stackoverflow.com/questions/13606573/disable-button-after-submit-with-jquery/36845948 – Oniel Telies May 24 '21 at 14:08
20

You need to also set the Button's UseSubmitBehavior property to false.

Web browsers do not include disabled elements in a form's POST data, even if the element happens to be the button that triggered the form submission in the first place. Unfortunately, ASP.NET WebForms' single-form-page design relies on that bit of information to know which control raised the PostBack and which event handler to execute (i.e. Button1.On_Click).

Switching to UseSubmitBehavior="false" injects a __doPostBack('Button1', '') in the client-side onclick handler to work around that problem. Then, even if you disable the Button, the __doPostBack parameter lets ASP.NET know which control raised the PostBack and which events to fire on the server-side.

Dave Ward
  • 59,815
  • 13
  • 117
  • 134
  • 1
    I agree. See http://stackoverflow.com/a/11832053/8479 below for an example that does this and uses client-side validation. – Rory Apr 17 '13 at 19:26
17

Most of this solutions provided above that suggest disabling won't work because you won't get a PostBack. This is the simplest and cleanest working solution I've seen:

OnClientClick="if(this.value === 'Saving...') { return false; } else { this.value = 'Saving...'; }"
Michael Socha
  • 1,748
  • 1
  • 16
  • 17
  • 3
    This should really be the answer. One more improvement that you can do is to add a setTimeout that will change back the text to the original Text. var tempText=this.value; this.value='Saving...'; setTimeout(function (){this.value=tempText;},4000); – illinoistim Aug 25 '17 at 19:28
  • Shows Saving message when the Required Field Validation Fails. – Sixthsense Feb 06 '23 at 05:01
11

To circumvent all validation and validation group issues, I found it easiest to use the window.onbeforeunload event, like so

<script type = "text/javascript">
function DisableButton() {
    document.getElementById("<%=Button1.ClientID %>").disabled = true;
}
window.onbeforeunload = DisableButton;
</script>

The above script disables the ASP.Net Button as soon as the page is ready to do a PostBack including validation or the ASP.Net form is submitted.

Disable ASP.Net button after click to prevent double clicking

wezzix
  • 1,984
  • 1
  • 19
  • 18
  • This does the trick. The above solutions were problematic when I try to implement. The Only drawback with this solution is that it does disable the button immediately, it executes as mentioned right before unload, so potentially users could click twice if code takes too long – DaniDev Feb 11 '16 at 23:24
  • 1
    I can't rule that out, but I just did a bit of simple testing, and no it appears that the button is disabled the instant that I release the mouse button with no visible delay. There is no way that I could click it again (also verified by Chrome developer tools). My finger is slower by order of magnitude. I would be interested to hear if anyone manages to beat onbeforeunload ;) – wezzix Feb 12 '16 at 06:29
  • I agree, in most instances it would be extremely fast. However there could be a scenario where the was OnUserClick= which executed a prolonged script prior to the submit. – DaniDev Feb 12 '16 at 18:12
4

I found that link very useful to solve this problem Disable ASP.Net button after click to prevent double clicking

I hope that can help :)

Ahmed Elbatt
  • 1,028
  • 1
  • 14
  • 20
  • I use now ***onbeforeunload*** for avoid _close Window Browser , Alt + F4, F5_ and I control **Postbacks**. How use it ***onbeforeunload*** for both cases ? – Kiquenet Nov 02 '17 at 10:27
2

I usually add this method to my BasePage for reuse.

This code handle validations too

/// <summary>
///  Avoid multiple submit
/// </summary>
/// <param name="button">The button.</param>
/// <param name="text">text displayed on button</param>
public void AvoidMultipleSubmit(Button button,string text="wait..." )
{
    Page.ClientScript.RegisterOnSubmitStatement(GetType(), "ServerForm", "if(this.submitted) return false; this.submitted = true;");
    button.Attributes.Add("onclick", string.Format("if(typeof(Page_ClientValidate)=='function' && !Page_ClientValidate()){{return true;}}this.value='{1}';this.disabled=true;{0}",
        ClientScript.GetPostBackEventReference(button, string.Empty),text));
}
giammin
  • 18,620
  • 8
  • 71
  • 89
1

Advantages

  • Works out of the box for all buttons
    • Even buttons that did not trigger the submit will be disabled.
    • LinkButtons will also be disabled.
  • Works with UpdatePanels (ie, partial and asynchronous postbacks)
  • Works for full postbacks
  • Won't disable buttons when validation prevents postback
  • Button press, enter-key press and AutoPostBack events will cause buttons to become disabled

Limitations

† Most other solutions I have seen have these same limitations

  • Relies on jQuery
  • Only works for ASP forms
  • If the user clicks the browser's cancel button after submission, the user will not be able to submit again and may get confused.
  • There remains other ways that a user could initiate a postback:
    • Submit using the enter key
    • Autopostback events

Code

Simply place this snippet at the bottom of your HTML code before the closing </body> tag.

<script type="text/javascript">
    jQuery(function ($) {

        /*
         * Prevent Double Submit
         * ---------------------
         * Disables submit buttons during form submission and asp async postbacks
         */

        // class name assigned to disabled :submit elements
        var disabledClass = 'asp-postback-disable';

        // selector for buttons and other elements that may cause a postback
        var submittableSelector = [
            'a[href^="javascript:__doPostBack"]',
            ':submit'
        ].join(",");

        // returns false; used to prevent event bubbling
        function returnFalse() { return false; }

        // logs errors
        function error(ex) {
            if (typeof console === 'object' && console.error != null) {
                console.error('Prevent Double Submit Error:', ex);
            }
        }

        // disables :submit elements
        function disableSubmit() {
            try {
                $(submittableSelector, 'form')
                    .addClass(disabledClass)
                    .on('click.asp-postback-disable', returnFalse);
            }
            catch (ex) { error(ex); }
        }

        // enables :submit elements
        function enableSubmit() {
            try {
                $('.asp-postback-disable,' + submittableSelector, 'form')
                    .removeClass(disabledClass)
                    .off('click.asp-postback-disable', returnFalse);
            }
            catch (ex) { error(ex); }
        }

        // Handle async postbacks
        if (typeof Sys === 'object') {
            var prm = Sys.WebForms.PageRequestManager.getInstance();
            prm.add_beginRequest(function (s, e) { disableSubmit(); });
            prm.add_endRequest(function (s, e) { enableSubmit(); });
        }
        else {
            error('Sys is undefined.');
        }

        // Handle navigation (eg, Full postback)
        $(window).bind('beforeunload', function (e) {
            disableSubmit();
        });

    });
</script>

<style type="text/css">
    .asp-postback-disable { opacity: 0.25; }
</style>
sparebytes
  • 12,546
  • 3
  • 21
  • 32
0

After searching for a while, I came up with this solution.

$('form').submit(function () {
    $('input[type=submit][data-loading]').addClass('disabled');

    if ($(this).data('submitted') == true) {
        $('input[type=submit][data-loading]').attr('disabled', 'disabled');
        return false;
    }

    $(this).data('submitted', true);
});

The problem with the UseDefaultBehavior solution is that the Enter key stops not submitting the form which is used a lot. I am assuming that a considerable percentage of users try enter instead of clicking.

Appulus
  • 18,630
  • 11
  • 38
  • 46
Fabio Milheiro
  • 8,100
  • 17
  • 57
  • 96
0

You can also hide the button or change it for a loading gif to maintain feedback

$(document).on('submit','form',function (e) {
    $("input.SubmitButton").hide();
    // or change if to an loading gif image.
    return true;
});
Zac Faragher
  • 963
  • 13
  • 26
EduLopez
  • 721
  • 7
  • 18
0

From an aspx.cs file you can add the script to address this (this is the only solution worked for me and was provided by: wexxix)

//Declaring the string to hold the script
string doubleClickScript = @"<script type='text/javascript'>
                                    function DisableButton() {
                                    document.getElementById('YOURBUTTONID').disabled = true;
                                }
                                window.onbeforeunload = DisableButton;
                                </script>";
//Injecting the script to the aspx page.        
ClientScript.RegisterStartupScript(this.GetType(), "DoubleClickScript", doubleClickScript);

Obviously you can just add the script to the page, I just used like that since I just had access to the customer C# code. Thanks

Ernest
  • 2,039
  • 24
  • 19
0

You can also kinda "hack it" through by create a client-side button with the same style, hide the "original" Server-side button and using javascript to disable the HTML button/call the original button to click.

In the next postback, it will automatically revert your change on client-side button :).

<asp:Button ID="btnSubmitQuote" class="btn btn-red btn-block" runat="server" Text="Submit Quote" style="display:none;" OnClick="btnSubmitQuote_Click" UseSubmitBehavior="false" />

<button id="btnSubmitQuoteClient"  class="btn btn-red btn-block" onclick ="disableBtn(this);">Submit Quote</button>
<script type="text/javascript">
 function disableBtn(t) {
    t.setAttribute('disabled', 'disabled');
    var btn = document.getElementById('<%=btnSubmitQuote.ClientID %>');
    btn.click();
  }

ManNguyenIO
  • 23
  • 1
  • 3
0

In the Page_Load event of your form put this line:

btnSubmit.Attributes.Add("onclick", " this.disabled = true; " + ClientScript.GetPostBackEventReference(btnSubmit, null) + ";");

Source: dotnetodyssey.com

SubqueryCrunch
  • 1,325
  • 11
  • 17
0

One thing you can do is after clicking it hide it in the client side and show some loader images.

Or if its a form or something you can add recaptcha

Mahesh KP
  • 6,248
  • 13
  • 50
  • 71
-3

Here is a quick solution. Set the width to 0 when they click on it. It will still submit but they will not be able to click it again. If you want to show it again in the scenario that there is a validation error then you can set the Width back to it original value on the server side click event.

OnClientClick="this.width=0;"
Pascal Belloncle
  • 11,184
  • 3
  • 56
  • 56