Sunday, April 11, 2010

Click Once Only - Dealing with Obsessive Compulsive Users

Click. Click. Clickclickclick...

Some users just can’t control themselves. They see a button, they click it. And once is never enough.

It’s no coincidence that the only group of professionals, besides programmers, who refer to their clientele as users are drug dealers.

Harmless enough in the privacy of ones home, this frenetic clicking behavior can wreak havoc on web applications, which, stateless as they are, handle each form submission as a separate request.

The Usability Straight Jacket

One way of saving our poor users from themselves is to disable that darn submit button, post click and post haste.

Our first impulse is to add some sneaky JavaScript to the submit button:
onclick="this.disabled=true;return true;"

However, you’ll soon notice a problematic side effect for even trivial forms such as this:

<asp:ValidationSummary runat="server" ID="vldSummary" HeaderText="Please correct the errors below:"
ShowSummary="false" DisplayMode="BulletList" ShowMessageBox="true"  />

<asp:Label runat="server" ID="lblFirstName" Text="First Name" AssociatedControlID="txtFirstName"></asp:Label>

<asp:TextBox runat="server" ID="txtFirstName" ></asp:TextBox>

<asp:RequiredFieldValidator runat="server" ID="reqValFirstName" ControlToValidate="txtFirstName" Display="Dynamic" Text="*" ErrorMessage="Enter a First Name" EnableClientScript="true"></asp:RequiredFieldValidator>
<br/>

<asp:Button runat="server" ID="btnSave" Text="Save" OnClick="btnSave_Click" />

Note the RequiredFieldValidator control. If validation errors occur on submission, the user will never get a second chance to submit the form because we disable the submit button onclick!


A 3-Step Solution

Obviously, more work is required. To cut a long story short:

  1. Change the submit button to a regular button that will not trigger form validation

    <asp:Button runat="server" ID="btnSave" Text="Save" CssClass="button" OnClick="btnSave_Click" OnClientClick="submitOnce(this);" UseSubmitBehavior="false" CausesValidation="false" />

    Skip this step, as some online articles do, and form validation will fire twice - you'll receive the “errors” popup twice

  2. Disable the button only if the form is valid

    function submitOnce(myButton){
    // Client side validation
    if (typeof(Page_ClientValidate) == 'function') {
    if (Page_ClientValidate() == false)
    { 
    
    return false; 
    }
    }
    
    //make sure the button is not of type "submit" but "button"
    if (myButton.getAttribute('type') == 'button') {
    // disable the button
    myButton.disabled = true;
    myButton.value = "processing...";
    }
    return true;
    }




  3. Since our button no longer has validation functionality built-in, we need to enforce validation in the server-side handler as well.

    protected void btnSave_Click(object sender, EventArgs e)
    {
    //VALIDATE
    Page.Validate();
    if (!Page.IsValid) return;
    
    //...do your magic...
    
    }
Thus our trigger-happy users click away to their hearts' content without fear of bringing on an apocalypse.

2 comments:

maybusher said...

This technique doesn't work with an asp:FileUpload control on the same page as it completely removes the file from the control once you click the button control.

طائر النورس said...
This comment has been removed by the author.