:::: MENU ::::

Monday, December 8, 2008

When building web applications, we've had a "defect" reported a number of times where a user presses a button twice in quick succession and causes a postback twice, typically causing whatever server-side code you've written to run twice.

Fellow developers usually dismiss this "defect" and say "can't the user just press the button once and wait?". Short answer, NO.

I've solved this in the past a few different ways.

For long running tasks I use BusyBoxDotNet. This basically uses the same concept as the ModalPopup through the AJAX Control Toolkit, but it hooks into the browser's onbeforeunload event. As it places a modal popup over the page, it prevents the user from pressing the submit button again.

This week, I needed a quick and easy way to prevent a user from submitting twice, and found it thanks to jQuery.

Screenshot

On the screenshot above, you can see that I've got a TextBox (which has a RequiredFieldValidator). In my button press event, I've got a Thread.Sleep(1000) to simulate a long running task.

If the user tries clicking the textbox after the page has already submitted, you get the alert message above.

Show me the code....

The magic happens in the following piece of javascript code...

Breaking it down.

Add a reference to the jQuery library, then call "noConflict()". (I like to call jQuery by its name, not using $)

I keep a javascript variable called "submitted" which initially is set to false.

Using jQuery, I hook up an event handler for the document ready event. This function finds (using jQuery selectors) the Page's Form.ClientID (so you can call the form what you want). When "submit" is called on the form, run the event handler.

I have to wrap "Page_IsValid" in a try..catch as Page_IsValid may NOT be on the page. This happens when there are no validators on the page.

If the form is valid, and it hasn't been submitted already, then all we do is update the "submitted" variable to TRUE.
If the form is valid, but the page HAS been submitted, then we call "preventDefault()" which stops form submission, and alert() to the user.

Important Notes

The important part here is that when we subscribe to the "submit" event in jQuery, it APPENDS our code to whatever is already there, it DOES NOT replace the code. I've struggled in the past with trying to get this to work, as you need to check if the form is submitted AFTER all the ASP.NET validators have run.

In the past some of the things I've tried are:

Using the Page.RegisterOnSubmitStatement()

This registers the javascript function before the WebForm_OnSubmit() function call.

Creating my own FORM class by overriding HtmlForm

I quickly tried this and tried to override OnPreRender() and RenderAttributes() and could never get my javascript AFTER the WebForm_OnSubmit() code.

Disabling / hiding buttons after they've been pressed

This is probably the easiest method of stopping submission of a page twice, but you have to be careful you don't disable the button BEFORE you check for validation errors, otherwise your user will never be able to submit a page.

Use BusyBoxDotNet

For really long running postbacks (eg payment gateway transactions), we use BusyBoxDotNet. As all our sites are hosted at WebCentral we've had to roll our own version to ensure it runs under a partial trust environment.

More