23

having a slight problem with an ASP.net page of mine. If a user were to double click on a "submit" button it will write to the database twice (i.e. carry out the 'onclick' method on the imagebutton twice)

How can I make it so that if a user clicks on the imagebutton, just the imagebutton is disabled?

I've tried:

<asp:ImageButton 
     runat="server" 
     ID="VerifyStepContinue" 
     ImageUrl=image src 
     ToolTip="Go" 
     TabIndex="98" 
     CausesValidation="true" 
     OnClick="methodName" 
     OnClientClick="this.disabled = true;" />

But this OnClientClick property completely stops the page from being submitted! Any help?

Sorry, yes, I do have Validation controls... hence the icky problem.


Working on this still, up to this point now:

ASP code:

 <asp:TextBox ID="hidToken" runat="server" Visible="False" Enabled="False"></asp:TextBox>
 ...
 <asp:ImageButton runat="server" ID="InputStepContinue" Name="InputStepContinue" ImageUrl="imagesrc" ToolTip="Go" TabIndex="98" CausesValidation="true" OnClick="SubmitMethod" OnClientClick="document.getElementById('InputStepContinue').style.visibility='hidden';" />

C# code:

         private Random
    random = new Random();


    protected void Page_Load(object sender, EventArgs e)
    {
        //Use a Token to make sure it has only been clicked once.
        if (Page.IsPostBack)
        {
            if (double.Parse(hidToken.Text) == ((double)Session["NextToken"]))
            {
                InputMethod();
            }
            else
            {
                // double click
            }
        }

        double next = random.Next();

        hidToken.Text = next + "";
        Session["NextToken"] = next;

Actually... this nearly works. The double click problem is pretty much fixed (yay!) The image still isn't hidden though.

6 Answers 6

21

The general approach is twofold.

Serverside:

  1. On load of the page, generate a token (using System.Random), save it in the session, and write it to a hidden form field
  2. On submit, check that the hidden form field equals the session variable (before setting it again)
  3. Do work

Clientside:

Similar to what you have, but probably just hide the button, and replace it with some text like 'submitting'.

The important thing to note, client side, is that the user may cancel the post by hitting 'escape', so you should consider what to do here (depending on how far along they are the token won't be used, so you'll need to bring the button back from being disabled/hidden).

Complete example follows:

C# (includes code to see it in action):

<html>
<head runat="server">
    <title>double-click test</title>
    <script language="c#" runat="server">
    private Random
        random = new Random();

    private static int
        TEST = 0;

    public void Page_Load (object sender, EventArgs ea)
    {
        SetToken();
    }

    private void btnTest_Click (object sender, EventArgs ea)
    {
        if( IsTokenValid() ){
            DoWork();
        } else {
            // double click
            ltlResult.Text = "double click!";
        }
    }

    private bool IsTokenValid ()
    {
        bool result = double.Parse(hidToken.Value) == ((double) Session["NextToken"]);
        SetToken();
        return result;
    }

    private void SetToken ()
    {
        double next = random.Next();

        hidToken.Value       = next + "";
        Session["NextToken"] = next;
    }


    private void DoWork ()
    {
        TEST++;
        ltlResult.Text = "DoWork(): " + TEST + ".";
    }
    </script>
</head>
<body>
    <script language="javascript">
        var last = null;
        function f (obj)
        {
            obj.src = "http://www.gravatar.com/avatar/4659883ec420f39723c3df6ed99971b9?s=32&d=identicon&r=PG";
            // Note: Disabling it here produced strange results. More investigation required.
            last = obj;
            setTimeout("reset()", 1 * 1000);
            return true;
        }

        function reset ()
        {
            last.src = "http://www.gravatar.com/avatar/495ce8981a5127a9fd24bd72e7e3664a?s=32&d=identicon&r=PG";
            last.disabled = "false";
        }
    </script>
    <form id="form1" runat="server">
        <asp:HiddenField runat="server" ID="hidToken" />
        <asp:ImageButton runat="server" ID="btnTest"
            OnClientClick="return f(this);"
            ImageUrl="http://www.gravatar.com/avatar/495ce8981a5127a9fd24bd72e7e3664a?s=32&d=identicon&r=PG" OnClick="btnTest_Click" />
        <pre>Result: <asp:Literal runat="server" ID="ltlResult" /></pre>
    </form>
</body>
</html>
Sign up to request clarification or add additional context in comments.

14 Comments

There's no built-in, simple way of handling this problem in ASP.Net?
MusiGenesis: All I know is I now have 7777 rep and I never want a single bit more (ffonline.com/media/guides/ff7/ffvii_faq_lucky7.txt) (And no).
@silky: one more reason ASP.Net sucks Cheez Whiz through a flex straw. Sigh. They could have just designed ASP.Net as a sensible web development platform instead trying to let developers pretend they were still coding Windows application, but nooooooo ...
@silky: A small nitpick - you shouldn't use a static Random like this in an .aspx page without some locking around it.
Alright. Out of embarassment of getting it slightly wrong, I've written a complete example. I think it should work (javascript to set disable may be slightly wrong). Please test and let me know. For some reason I can't rest until it works ... :P
|
6

If you have validation on the page, disabling the button client side gets a little tricky. If validation fails, you don't want to disable the button. Here's a snippet that adds the client side event handler:

private void BuildClickOnceButton(WebControl ctl)

{

System.Text.StringBuilder sbValid = new System.Text.StringBuilder();

sbValid.Append("if (typeof(Page_ClientValidate) == 'function') { ");

sbValid.Append("if (Page_ClientValidate() == false) { return false; }} ");

sbValid.Append(ctl.ClientID + ".value = 'Please wait...';");

sbValid.Append(ctl.ClientID + ".disabled = true;");

// GetPostBackEventReference obtains a reference to a client-side script 
// function that causes the server to post back to the page.

sbValid.Append(ClientScript.GetPostBackEventReference(ctl, ""));

sbValid.Append(";");

ctl.Attributes.Add("onclick", sbValid.ToString());

}

See this asp.net thread for more info.

Update: the above code would be used to add the OnClientClick handler in code behind. You could also write the javascript in your aspx markup like so:

<script type="text/javascript">
function disableButton(button)
{
    // if there are client validators on the page
    if (typeof(Page_ClientValidate) == 'function') 
    {
        // if validation failed return false
        // this will cancel the click event
        if (Page_ClientValidate() == false) 
        { 
            return false; 
        }
    }

    // change the button text (does not apply to an ImageButton)
    //button.value = "Please wait ...";
    // disable the button
    button.disabled = true;

    // fire postback
    __doPostBack(button.id, '');
}
</script>

<asp:ImageButton runat="server" ID="VerifyStepContinue" ImageUrl="button.png" 
    ToolTip="Go" TabIndex="98" CausesValidation="true" OnClick="methodName" 
    OnClientClick="return disableButton(this);" />

7 Comments

This looks like what I'm after, but not quite sure how to work with this... which variables would I need to change for mine? I've looked at the forum post and it seems to be right, but I can't quite get at it.
Again, doesn't work... when I try to use this, it still disables everything.
Do you get a javascript error? Is the script disabling more than just the image button?
Disabling more than just the image button, yes.
This is beautiful. IMHO, it should be an ASP .NET official way to handle "prevent form double-submit". Very nicely done.
|
3

I have solved this by setting a hidden field on the client click before hitting the server.

Then in the server I check the hidden field and if the value is for example something 'FALSE' that might mean I can or cannot of the action.

Comments

0

Similar to Silky's client-side response, I usually make two buttons that look alike except that the second button is disabled and hidden. OnClientClick of the normal button swaps the display styles of the two buttons so that the normal button is hidden and the disabled button is shown.

Comments

0

The double-click feature is a server-side implementation to prevent processing that same request which can be implemented on the client side through JavaScript. The main purpose of the feature is to prevent processing the same request twice. The server-side implementation does this by identifying the repeated request; however, the ideal solution is to prevent this from occurring on the client side.

In the HTML content sent to the client that allows them to submit requests, a small validation JavaScript can be used to check whether the request has already been submitted and if so, prevent the online shopper from submitting the request again. This JavaScript validation function will check the global flag to see if the request has been submitted and, if so; does not resubmit the request. If the double-click feature is disabled on the server, it is highly recommended that the JSP and HTML pages implement this JavaScript prevention.

The following example prevents the form from being submitted more then once by using the onSubmit() action of the form object:

...
<script>
var requestSubmitted = false;
       function submitRequest() {
              if (!requestSubmitted ) {
                     requestSubmitted  = true;
                     return true;
              }
              return false;
       }
</script>
...

       <FORM method="POST" action="Logon" onSubmit="javascript:submitRequest()">
              ......
       </FORM> 

1 Comment

The onsubmit code should look like this: onsubmit="return submitRequest()".
0

for those who just want to do a quick fix , just hide it and show another button that has no events

<asp:Button ID="RedeemSubmitButton" runat="server" Text="Submit to Redeem" OnClick="RedeemSubmitButton_Click" OnClientClick="hideit();" />
<asp:Button ID="RedeemSubmitButtonDisabled" style="display:none;" runat="server" Text="please wait" OnClientClick="javascript:alert('please wait, processing');"  />
<script>
 function hideit() {



        var btn = $get('<%= this.RedeemSubmitButton.ClientID %>');
        var btn2 = $get('<%= this.RedeemSubmitButtonDisabled.ClientID %>');
        if (btn != null)
        {

            btn.style.display = 'none';
            btn2.style.display = 'block'
        }
 }
    </script>

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.