8

I have a asp.net app that I want to disable the buttons as soon as they are clicked in order to prevent multiple submissions. I'd like to use jquery for this as the site already liberally uses it anyway.

What I've tried is:

$(document).ready(function () {
    $("#aspnetForm").submit(function () {
        $('input[type=submit]', $(this)).attr("disabled", "disabled");
    })
});

The above will disable the button, and the page submits, but the asp.net button on click handler is never called. Simply removing the above and the buttons work as normal.

Is there a better way? Or, rather, what am I doing wrong?

UPDATE Okay, I finally had a little time to put a very simple page together.

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="SubTest.aspx.cs" Inherits="MyTesting.SubTest" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#form1").submit(function () {
                $('input[type=submit]', $(this)).attr("disabled", "disabled");
            });
        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:Button ID="Button1" runat="server" onclick="Button1_Click" Text="Button" />
        <asp:Button ID="Button2" runat="server" onclick="Button2_Click" Text="Button 2" />
    </div>
    </form>
</body>
</html>

The code behind looks like:

using System;

namespace MyTesting {
    public partial class SubTest : System.Web.UI.Page {
    protected void Page_Load(object sender, EventArgs e) {
        if (IsPostBack) {
            // this will execute when any button is pressed
            Response.Write("postback");
        }
    }
        protected void Button1_Click(object sender, EventArgs e) {
        // never executes
            System.Threading.Thread.Sleep(1000);
            Response.Write("Button 1 clicked<br />");
        } // method::Button1_Click

        protected void Button2_Click(object sender, EventArgs e) {
        // never executes
            System.Threading.Thread.Sleep(1000);
            Response.Write("Button 2 clicked<br />");
        } // method::Button2_Click
    }
}

When you click on a button it obviously disables the buttons, but NEITHER of the button clicks are run.

Rendered HTML

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head><title>

</title>
    <script src="Scripts/jquery-1.4.1.min.js" type="text/javascript"></script>
    <script type="text/javascript">
        $(function () {
            $("#form1").submit(function () {
                $('input[type=submit]', $(this)).attr("disabled", "disabled");
            });
        });
    </script>
</head>
<body>
    <form name="form1" method="post" action="SubTest.aspx" id="form1">
<div>
<input type="hidden" name="__VIEWSTATE" id="__VIEWSTATE" value="/wEPDwUKMTcxODU4OTc0MWRkParC5rVFUblFs8AkhNMEtFAWlU4=" />
</div>

<div>

    <input type="hidden" name="__EVENTVALIDATION" id="__EVENTVALIDATION" value="/wEWAwKB57WhCAKM54rGBgK7q7GGCC6LlWKFoij9FIBVuI0HOVju/fTy" />
</div>
    <div>
        <input type="submit" name="Button1" value="Button" id="Button1" />
        <input type="submit" name="Button2" value="Button 2" id="Button2" />
    </div>
    </form>
</body>
</html>
NotMe
  • 87,343
  • 27
  • 171
  • 245
  • Very interesting gotchya – Chris Fewtrell May 28 '10 at 21:37
  • I think I know exactly what's going on now. Because the button attribute disabled is set, the asp.net engine says "oh, the button is disabled, don't run it's post back code!" However, because a submit was sent, it goes ahead and performs a regular post back... grr – NotMe May 28 '10 at 21:44

7 Answers7

7

You can do it a slightly different way, like this:

$(function () {
  $("#aspnetForm").submit(function () {
    $('input[type=submit]').click(function() { return false; });
  });
});

What this does is makes future clicks ineffective, basically making them do nothing. When you disable an input, it also removes the key/value pair from being submitted with the <form>, so your server-side action which is triggered by it doesn't work.

It's worth noting, in jQuery 1.4.3 you'll be able to shorten this down to:

$(function () {
  $("#aspnetForm").submit(function () {
    $('input[type=submit]').click(false);
  });
});
Nick Craver
  • 623,446
  • 136
  • 1,297
  • 1,155
  • I'm running 1.4.2 right now. the first one doesn't seem to stop multiple button presses; – NotMe May 21 '10 at 03:26
  • @Chris - Can you post your markup? Are you using submit buttons or possibly links as well? – Nick Craver May 21 '10 at 09:44
  • @Chris - can you post the *rendered* html? That's all the javascript's going to care about :) – Nick Craver May 28 '10 at 21:00
  • @Nick: rendered version is up. – NotMe May 28 '10 at 21:19
  • I have tried Nick's solution and it *does* work (in chrome and FF 3.6) – Chris Fewtrell May 28 '10 at 21:43
  • I'm upvoting and accepting this answer as the only viable solution. Setting a button to disabled screws with asp.net's post back mechanism. However, if I combine the answer here with a step that changes the css class of the button to grey it out, then it achieves basically the same effect. Thanks – NotMe May 28 '10 at 21:50
2

The approach of disabling the button before the submit has two effects: -

a) The button takes on the disabled appearance.

b) The button's value is not posted in the form parameters.

If the button's value is not being posted to the server, ASP.Net does not know which button was pressed and thus it does not run the relevent OnClick handler.

To verify add the following to your code behind

protected void Page_Load(object sender, EventArgs e)
{
    Response.Write("Load " + IsPostBack + "<br />");
    foreach (string s in Request.Form.AllKeys)
    {
        Response.Write(string.Format("s:'{0}' = {1}<br />", s, Request.Form[s]));
    }
}

And then run the page (both with J.S. to disable the buttons and without). If the button's value is not being posted to the server, ASP.Net does not know which button was pressed and thus it does not run the relevent OnClick handler.

Chris Fewtrell
  • 7,555
  • 8
  • 45
  • 63
2

Just another observation. Alternatively, you can lock UI with a nice overlay busy message.

The Mark-up part:

$(function() { // when document has loaded

    ($.unblockUI); //unlock UI

    //Show busy message on click event and disable UI
    $('#btnHelloWorld').click(function() {
    $.blockUI({ message: '<h4><img src="busy.gif" />Please wait...</h4>' });

    });

});

<asp:Button ID="btnHelloWorld" runat="server" Text="Hello World" /><br/>

The Code behind:

   Protected Sub btnHelloWorld_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnHelloWorld.Click
        Label1.Text = "Hello World"
        Threading.Thread.Sleep(5000)
    End Sub

Check out jQuery BlockUI Plugin

Tola
  • 2,401
  • 10
  • 36
  • 60
1

I just wanted to add an additional resolution. We decided to just completely remove the button once it was clicked and replace it with some text.

To do this we did:

$(function () {
    $(".DisableButton").click(function () {
        $(this).hide();
        $(this).after('<p>Please Wait.  Retrieving information.  This may take up to 60 seconds.</p>');

    });
});

Note that this hides the button then injects some html after the buttons code. Hiding it allows .Net to go ahead and run the onclick handler during post back while removing it as a clickable thing on the screen.

NotMe
  • 87,343
  • 27
  • 171
  • 245
0

The answer provided by Nick Craver is by far the best solution that I've found anywhere on the net. There is one situation, however, where the solution does not work well - when the form contains submit buttons within an UpdatePanel with it's UpdateMode property set to "Conditional" and/or ChildrenAsTriggers property set to false.

In these situations, the contents of the update panels are not automatically refreshed when the async postback has completed. So if these update panels contained any submit buttons then the given solution would effectively leave these buttons permanently disabled.

The following enhancement to the solution handles this problem by re-enabling the buttons after an async, or 'partial', postback:

var canProcessClicks = true;

if (typeof (Sys) != 'undefined') {
    // handle partial-postback
    var requestManager = Sys.WebForms.PageRequestManager.getInstance();
    requestManager .add_initializeRequest(function() {
        // postback started
        canProcessClicks = false;
    });
    requestManager .add_endRequest(function() {
        // postback completed
        canProcessClicks = true;
    });
}

$(function () {
    $('input[type=submit]').on("click", function () {
        return canProcessClicks ;
    });
    $("#aspnetForm").submit(function () {
        if (typeof (Sys) != 'undefined' && Sys.WebForms.PageRequestManager.getInstance().get_isInAsyncPostBack()) {
            // this is an async postback so ignore because this is already handled
        } else {
            // full postback started
            canProcessClicks = false;
        }
    });
});
Kev
  • 1,832
  • 1
  • 19
  • 24
0

Add this attribute to your button:

usesubmitbehavior="False"

This will insert something like the following into onclick:

javascript:WebForm_DoPostBackWithOptions(new WebForm_PostBackOptions("ctl00$Main$Tabs$SaveTab$Cancel", "", true, "", "", false, false))

This code will cause a post back even if the button is disabled. Showing a confirmation dialog and allowing the post back to be cancelled gets a little more interesting:

    var click = $("[id$='_Cancel']")[0].onclick;
    $("[id$='_Cancel']")[0].onclick = null;
    $("[id$='_Cancel']").bind('click', function (event) { addFeeSchedule.onCancelClick(event) });
    $("[id$='_Cancel']").bind('click', click);

In order to prevent the post back from occurring immediately, remove the onclick code inserted by .net and bind it after your own function using jQuery. Use event.stopImmediatePropagation(), to prevent the post back:

onCancelClick: function (event) {

    var confirmResponse;

    confirmResponse = confirm('No fee schedule will be created.\n\nAre you sure you want to cancel?');

    if (confirmResponse == true) {

        showWait();
        event.target.disabled = 'true';

    } else {

        event.stopImmediatePropagation();

    }

},
Keith Walton
  • 5,211
  • 6
  • 39
  • 53
-3

For this you have to use input button attribute disable all the controls

<script language="javascript" type="text/javascript">
    function MyDisableFunction() {
        alert(`Now You Postback Start`);
        $(":input").attr("disabled", true);
        return true;
    }

</script>

Fore more detail check this link

Alex K
  • 22,315
  • 19
  • 108
  • 236
Vinay
  • 1
  • 1