views:

4223

answers:

16

I have a button that I would like to disable when the form submits to prevent the user submitting multiple times.

I have tried naively disabling the button with javascript onclick but then if a client side validation that fails the button remains disabled.

How do I disable the button when the form successfully submits not just when the user clicks?

This is an ASP.NET form so I would like to hook in nicely with the asp.net ajax page lifecycle if possible.

+2  A: 

Disable the button at the very end of your submit handler. If the validation fails, it should return false before that.

However, the JavaScript approach is not something that can be relied upon, so you should have something to detect duplicates on the server as well.

Jim
A: 

Not sure if this will help, but there's onsubmit event in form. You can use this event whenever the form submit (from any button or controls). For reference: http://www.htmlcodetutorial.com/forms/_FORM_onSubmit.html

ChRoss
+3  A: 

The following function is useful without needing the disabling part which tends to be unreliable. Just use "return check_submit();" as part of the onclick handler of the submit buttons.

There should also be a hidden field to hold the form_submitted initial value of 0;

<input type="hidden" name="form_submitted" value="0">

function check_submit (){
         if (document.Form1.form_submitted.value == 1){
          alert("Don't submit twice. Please wait.");
          return false;
         }
         else{
          document.Form1.form_submitted.value = 1;
          return true;
         }
         return false;
    }
Turnkey
A: 

A solution will be to set a hidden field when the button is clicked, with the number 1.

On the button click handler first thing is to check that number if it is something other than 1 just return out of the function.

David Basarab
A: 

You may also be able to take advantage of the onsubmit() javascript event that is available on forms. This event fires when the form is actually submit and shouldn't trap until after the validation is complete.

CodeRot
+12  A: 

Give this a whirl:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Threading;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {

         // Identify button as a "disabled-when-clicked" button...
         WebHelpers.DisableButtonOnClick( buttonTest, "showPleaseWait" ); 
    }

    protected void buttonTest_Click( object sender, EventArgs e )
    {
        // Emulate a server-side process to demo the disabled button during
        // postback.
        Thread.Sleep( 5000 );
    }
}



using System;
using System.Web;
using System.Web.UI.WebControls;
using System.Text;

public class WebHelpers
{
    //
    // Disable button with no secondary JavaScript function call.
    //
    public static void DisableButtonOnClick( Button ButtonControl )
    {
        DisableButtonOnClick( ButtonControl, string.Empty );    
    }

    //
    // Disable button with a JavaScript function call.
    //
    public static void DisableButtonOnClick( Button ButtonControl, string ClientFunction )
    {   
        StringBuilder sb = new StringBuilder( 128 );

        // If the page has ASP.NET validators on it, this code ensures the
        // page validates before continuing.
        sb.Append( "if ( typeof( Page_ClientValidate ) == 'function' ) { " );
        sb.Append( "if ( ! Page_ClientValidate() ) { return false; } } " );

        // Disable this button.
        sb.Append( "this.disabled = true;" ); 

        // If a secondary JavaScript function has been provided, and if it can be found,
        // call it. Note the name of the JavaScript function to call should be passed without
        // parens.
        if ( ! String.IsNullOrEmpty( ClientFunction ) ) 
        {
            sb.AppendFormat( "if ( typeof( {0} ) == 'function' ) {{ {0}() }};", ClientFunction );  
        }

        // GetPostBackEventReference() obtains a reference to a client-side script function 
        // that causes the server to post back to the page (ie this causes the server-side part 
        // of the "click" to be performed).
        sb.Append( ButtonControl.Page.GetPostBackEventReference( ButtonControl ) + ";" );

        // Add the JavaScript created a code to be executed when the button is clicked.
        ButtonControl.Attributes.Add( "onclick", sb.ToString() );
    }
}
rp
thanks rp. this looks awesome.
Brownie
Wow! You look to be an enterprise level coder! :)
Adhip Gupta
rp. one small change I had to make was to pass my validationgroup name to the Page_ClientValidate() method. Thanks for the code!
Brownie
i'm not a asp guy... but to write so much code instead of onsubmit="this.button.disable=true" or smth like that in <form> tag is kinda... weird? :|
Ionut Staicu
Staicu: your solution does not take into account whether validation passes or not. With your solution if the validation fails the save button is left disabled.
Brownie
Seems to take Validation into account to me Brownie.
Adam Nofsinger
Great bit of code been looking for somthing like this for a while
TheAlbear
Great code, I ended up making it an extension method for all my buttons.public static void DisableButtonOnClick(this Button ButtonControl, string ClientFunction)
BigBlondeViking
50 lines of server-side code required to accomplish a client-side subtlety? No thanks!!
Josh Stodola
Give the guy a break, Josh: some of those lines are blank, many are "using" statements, and quite a bit are comments! :-)
Steve J
Josh--Firmly entrenched now with jQuery and lots of client-side work, my approach may be a little different now--but only because I'm less less hooked to server-side controls now. That said, if LOC is your metric, show me the client code in less code! Be sure to play along with ASP.NET validators and call a function if provided. (thanks for the defense, Steve J).
rp
+2  A: 

if the validation is successful, then disable the button. if it's not, then don't.

function validate(form) {
  // perform validation here
  if (isValid) {
    form.mySubmitButton.disabled = true;
    return true;
  } else {
    return false;
  }
}

<form onsubmit="return validate(this);">...</form>
nickf
A: 

This is an easier but similar method than what rp has suggested:

function submit(button) {
        Page_ClientValidate(); 
        if(Page_IsValid)
        {
            button.disabled = true;
        }
}

 <asp:Button runat="server" ID="btnSubmit" OnClick="btnSubmit_OnClick" OnClientClick="submit(this)" Text="Submit Me" />
Adhip Gupta
+1  A: 

Set the visibility on the button to 'none';


btnSubmit.Attributes("onClick") = document.getElementById('btnName').style.display = 'none';

Not only does it prevent the double submission, but it is a clear indicator to the user that you don't want the button pressed more than once.

Kyle B.
this is a good one.
MGOwen
...though I do prefer using the OnClientClick attribute, not the code-behind.
MGOwen
... and won't you need it to not disappear if client side validation fails?
MGOwen
+6  A: 

I'm not a huge fan of writing all that javascript in the code-behind. Here is what my final solution looks like.

Button:

<asp:Button ID="btnSubmit" runat="server" Text="Submit" OnClick="btnSubmit_Click" OnClientClick="doSubmit(this)" />

Javascript:

<script type="text/javascript"><!--
function doSubmit(btnSubmit) {
    if (typeof(Page_ClientValidate) == 'function' && Page_ClientValidate() == false) { 
        return false;
    }    
    btnSubmit.disabled = 'disabled';
    btnSubmit.value = 'Processing. This may take several minutes...';
    <%= ClientScript.GetPostBackEventReference(btnSubmit, string.Empty) %>;    
}
//-->
</script>
Adam Nofsinger
A: 

Just heard about the "DisableOnSubmit" property of an <asp:Button>, like so:

<asp:Button ID="submit" runat="server" Text="Save"
    OnClick="yourClickEvent" DisableOnSubmit="true" />

When rendered, the button's onclick attribute looks like so:

onclick="this.disabled=true; setTimeout('enableBack()', 3000);
  WebForm_DoPostBackWithOptions(new
  WebForm_PostBackOptions('yourControlsName', '', true, '', '', false, true))

And the "enableBack()' javascript function looks like this:

function enableBack()
{
    document.getElementById('yourControlsName').disabled=false;
}

So when the button is clicked, it becomes disabled for 3 seconds. If the form posts successfully then you never see the button re-enable. If, however, any validators fail then the button becomes enabled again after 3 seconds.

All this just by setting an attribute on the button--no javascript code needs to be written by hand.

Steve J
That would be great - but it doesn't exist in my version of ASP.NET. What version are you using!?
MGOwen
I was using the latest version at the time: Visual Studio 2008. I no longer work for that employer, so I can't verify anything else (service packs, .NET runtime version, etc.). Sorry for the delay in responding!
Steve J
Now that I think of it, I believe the page made use of AJAX, so this may have been an extension that the toolkit provided.
Steve J
A: 

Note that rp's approach will double submit your form if you are using buttons with UseSubmitBehavior="false".

I use the following variation of rp's code:

public static void DisableButtonOnClick(Button button, string clientFunction)
{
    // If the page has ASP.NET validators on it, this code ensures the
    // page validates before continuing.
    string script = "if (typeof(Page_ClientValidate) == 'function') { "
            + "if (!Page_ClientValidate()) { return false; } } ";

    // disable the button
    script += "this.disabled = true; ";

    // If a secondary JavaScript function has been provided, and if it can be found, call it.
    // Note the name of the JavaScript function to call should be passed without parens.
    if (!string.IsNullOrEmpty(clientFunction))
        script += string.Format("if (typeof({0}) == 'function') {{ {0}() }} ", clientFunction);

    // only need to post back if button is using submit behaviour
    if (button.UseSubmitBehavior)
        script += button.Page.GetPostBackEventReference(button) + "; ";

    button.Attributes.Add("onclick", script);
}
A: 

The correct (as far as user-friendliness is concerned, at least) way would be to disable the button using the OnClientClick attribute, perform the client-side validation, and then use the result of that to continue or re-enable the button.

Of course, you should ALSO write server-side code for this, as you cannot rely on the validation even being carried out due to a lack, or particular implementation, of JavaScript. However, if you rely on the server controlling the button's enabled / disabled state, then you basically have no way of blocking the user submitting the form multiple times anyway. For this reason you should have some kind of logic to detect multiple submissions from the same user in a short time period (identical values from the same Session, for example).

TomFromThePool
A: 

one of my solution is as follow:

add the script in the page_load of your aspx file

    HtmlGenericControl includeMyJava = new HtmlGenericControl("script");
    includeMyJava.Attributes.Add("type", "text/javascript");
    includeMyJava.InnerHtml = "\nfunction dsbButton(button) {";
    includeMyJava.InnerHtml += "\nPage_ClientValidate();";
    includeMyJava.InnerHtml += "\nif(Page_IsValid)";
    includeMyJava.InnerHtml += "\n{";
    includeMyJava.InnerHtml += "\nbutton.disabled = true;";
    includeMyJava.InnerHtml += "}";
    includeMyJava.InnerHtml += "\n}";
    this.Page.Header.Controls.Add(includeMyJava);

and then set your aspx button parameters as follow:

<asp:Button ID="send" runat="server" UseSubmitBehavior="false" OnClientClick="dsbButton(this);" Text="Send" OnClick="send_Click" />

Note that "onClientClick" helps to disable to button and "UseSubmitBehaviour" disables the traditional submitting behaviour of page and allows asp.net to render the submit behaviour upon user script.

good luck

-Waqas Aslam

A: 

Seems like this is the solution you are looking for. This will work with ASP.NET validations too.

http://praveenbattula.blogspot.com/2010/01/disable-button-in-onclick-and-process.html

Rare Solutions
A: 

this solution (rp) does not work in Firefox, which would generate double postbacks.

YB