This is a follow-up post, building on the foundation laid in ASP.NET AJAX username availability check. In this post, I assume you’ve read and understood the first post.

After originally implementing AJAX username availability checking in my applications, I noticed an edge case scenario that replayed itself too often to ignore. The availability check could potentially take longer than a particularly fast user would need to complete the form. To avoid any trouble in that scenario, I wanted to add a progress indicator to the checking process and disable the submit button’s until an available username was selected.


Adding the progress indicator

For the progress indicator, I basically copied the technique described in my CSS style as AJAX progress indicator post. I added another background image CSS class, progress:

.progress {
  background-image: url(spinner.gif);
}

Then, added this client script to the page:

// Hook the InitializeRequest event.
Sys.WebForms.PageRequestManager.getInstance().add_initializeRequest(Init);
 
function Init(sender, args) 
{
  // Change div's CSS class and text content.
  $get('UserAvailability').className = 'progress';
  $get('UserAvailability').innerHTML = 'Checking availability...';
}

This causes the div’s class to change to a spinning progress indicator animation when the partial postback begins, and changes the div’s text content to clarify what’s going on.

At the completion of the postback, the div’s content will be replaced by what’s generated in code-behind, so there’s no need to do anything on the client side for endRequest. The server-generated content will overwrite this temporary change and automatically replace the progress indicator with the username’s availability.

Preventing invalid submissions

I decided to declaratively start the button control off disabled, so that it defaults to blocking submissions until an available username is selected. Since I want to be able to manipulate its Enabled property in partial postbacks, I also enclosed it in an UpdatePanel:

<asp:UpdatePanel runat="server" ID="up2">
  <ContentTemplate>
    <asp:Button runat="server" ID="Button1" 
      Text="Sign me up!" Enabled="false" />
  </ContentTemplate>
</asp:UpdatePanel>

Next, I updated the username availability check to update the button’s enabled state appropriately:

if (Membership.GetUser(Username.Text) != null)
{
  UserAvailability.InnerText = "Username taken, sorry.";
  UserAvailability.Attributes.Add("class", "taken");
  Button1.Enabled = false;
}
else
{
  UserAvailability.InnerText = "Username available!";
  UserAvailability.Attributes.Add("class", "available");
  Button1.Enabled = true;
}

Now, at the same time the availability check’s result is displayed, the button will also be enabled or disabled depending on the availability of the username.

Because only the username TextBox, the availability div, and the Button are enclosed in UpdatePanels, only their contents will be replaced by partial postbacks. This is crucial so that other elements of the form aren’t reverted to their pre-postback state after the availability check. If your page has other UpdatePanels, make sure to set your UpdateModes and Triggers to properly isolate partial postback results.

Watch out for partial postbacks

Finally, I decided that I should also disable the submit button during availability checks. If a user chose an available username, but then changed it to something unavailable, they could sneak a submit in during the availability check’s callback. To prevent this I disabled the submit button, in the same InitializeRequest handler that displays the progress indicator:

$get('Button1').disabled = true;

This simply disables the button as soon as the partial postback begins. If the username ends up being available, the newly rendered button will be enabled, else it will remain disabled until the user chooses an available username.

In other words, no one with JavaScript enabled should be able to submit a registration for an invalid username now.

Bringing it all together

There are still several more improvements that could be made. For example, if the username is unavailable, we could suggest a few available variants of that username. However, I’m happy with these improvements as a solid first step toward improving the baseline user experience on my registration forms.

To clarify all of my rambling, convoluted source code snippets, here are the aspx, c#, css, and image files used throughout these two posts: