Click here to Skip to main content
15,881,381 members
Articles / Web Development / ASP.NET

ASP.NET Validation: Tamed

Rate me:
Please Sign up or sign in to vote.
4.63/5 (13 votes)
13 May 2006CPOL9 min read 82.1K   224   40   9
This article shows how to defeat the obstacles imposed by the ASP.NET validation system. Client-side control of validation is the main interest of this article, and the solution's core is JavaScript code.

Sample Image - ASPNET_Validation_Tamed.jpg

Introduction

Validation is one of the necessary tasks that every web systems developer will face at one point or another. Validation can be as simple as ensuring that data is input in fields (checking for empty fields), and as complex as ensuring that input conforms to a certain format (matching with Regular Expressions). ASP.NET (1.1) offers a collection of validation controls that (supposedly) help in validating web forms. These controls on the other hand, are not sufficient for the every day needs of most developers; they fail at many points I illustrate below. My code tries to fill some of the gaps, and some advice will point in the right direction of solving issues my code cannot solve.

Scope

My focus will be on providing client side control over validation. Thus, my code will be JavaScript in its core. C# code will be used to facilitate using the JavaScript code. Code to extend or recreate the existing validation controls is not within the scope of this article.

ASP.NET Validation Fails

The controls provided by ASP.NET fail in the following points:

  1. No ability to specify when validators work with respect to the clicked buttons.
  2. No ability to group validators together so that they can be activated or deactivated according to a certain client-side event.
  3. When hiding a certain control (on the client-side) by setting its style to 'display: none;', the validators become hidden but still active.
  4. A very important drawback is that these validators don't work on non-IE browsers.

Validation in Firefox

Firefox is a widely used web browser. Its market has grown to the extent where it competes with Internet Explorer. When the ASP.NET validators were made, non-IE browsers were not taken into consideration. That is evident in the fact that their client-side validation does not work on Firefox (I only tested Firefox). Some say that the emitted JavaScript is IE specific, but I noticed recently that there is not even any emitted JavaScript when the browser is Firefox. How does ASP.NET emit JavaScript for IE and none for Firefox? That is called Adaptive Rendering, where the browser is determined, and according to the determined browser, the controls are rendered differently.

So, my code works in IE only because validation works in IE only. What do we do in the case of non-IE browsers? We have to look at third party validation controls that generate compliant JavaScript. I found that the free DOMValidators are very good. My code works with DOMValidators.

The Solution

It is all in the JavaScript code. The script file has a collection of functions that will give developers the power to enable/disable validation on the client side. The script provides the following:

  1. Ability to specify when validators are active and when they are inactive. This can help in binding validators to certain buttons. For example, if we have (as illustrated in the picture) two input sections. The first is for Members, and the second is for New Users that wish to become Members. When a Member clicks the Login button, validation for the New Users section should not be active. So, if users want to login, they should only provide a Username and a Password, and not the fields of the New User section.
  2. Ability to group validation controls together under Groups. This way, we can disable/enable them according to group name.
  3. Ability to enable/disable the validators inside a certain container.
  4. Ability to enable/disable the validators that validate a certain control.
  5. Ability to hide a certain container with all the validators inside it (disable them, not just hide them).
  6. Give all this control without having to build new controls or even extend the existing ones.

The JavaScript

The JavaScript functions fall into three groups:

  1. Controlling validators that exist inside a certain container. If the container is not specified, then all validators in the page are affected (enableValidators, disableValidators).
  2. Controlling validators that validate a certain control X and are inside a control Y. If Y is not specified, then all controls in the page that validate X are affected (enableCTVValidators, disableCTVValidators).
  3. Controlling validators that belong to a specific group (enableGroupValidators, disableGroupValidators).

There is another group that enables showing/hiding a certain section of the page, disabling and hiding all the contained validators in the process (show, hide, show/hide). This group uses the functions in the three groups above.

Using Them

The above functions can be used by calling them using JavaScript. Such calls are usually inside the client-side event handlers of the action controls in our pages. For example, we can call enableValidators() inside the onclick event of the Login button.

C#
btnLogin.Attributes["onclick"] =
 "enableValidators('" + tblMember.ClientID + "');"+
 " disableValidators('" + tblNew.ClientID + "');";

The above code will make the btnLogin button enable all validators inside the table tblMember and disable all the validators inside the table tblNew.

We can also group some validators together by giving them a groupID. This should be done in the HTML view of our pages.

HTML
<asp:requiredfieldvalidator id="rfvLoginName"
   ErrorMessage="Username Required" Display="Dynamic"
  ControlToValidate="txtLoginName" groupID="Member" runat="server">
!</asp:requiredfieldvalidator>

and here is what happens in the code-behind:

C#
btnLogin.Attributes["onclick"] =
 "enableGroupValidators('Member'); disableGroupValidators('NewMember');";

The validators belonging to the group called Member are enabled, and those belonging to the group called NewMember are disabled, when the btnLogin button is clicked (clicked on the client side). The opposite behavior happens when clicking the btnSubmit button in this code:

C#
btnSubmit.Attributes["onclick"] = "enableGroupValidators('NewMember');" +
           " disableGroupValidators('Member');";

The validation for the whole page is re-enabled when any of the buttons loses focus. This is a suitable solution since the onblur event happens after our buttons are clicked.

For more examples of using these functions and the rest of the functions, please check the demo project that accompanies this article.

Server Side Validation

Although it is not the focus of this article, it is crucial that our page gets validated on the server side as well. That is due to the fact that client-side validation can be easily bypassed.

Since we are enabling/disabling validators on the client-side, and since on the server side there is no perception of the changes we make on the client side (validators still function on the server side even when we disable them on the client side), checking the Page.IsValid property will not do it. That is why we use this method:

C#
private bool checkIsValid(Control c)
{
   bool result = true;
   foreach( Control child in c.Controls)
   {
      if(child is BaseValidator && !((IValidator)child).IsValid)
      {
         return false;
      }
      result = result & checkIsValid(child);
   }
   return result;
}

The above method checks all validators inside a given control. If all the validators are valid, then the provided control is valid; otherwise, the whole control is not valid.

The JavaScript Detailed

This is not a required reading for those interested in using the code. This section is for those interested in knowing the JavaScript inner workings of the code.

There are two versions for every type of function, one that enables validation and one that disables it. Let us start from the top. In the Contained Validators part, there is the main traversal function that finds the intended validation controls and sets their status.

JavaScript
function traverseTree(status, control)
{
 if(control == null)
 {
  for(var i = 0; i < Page_Validators.length; i++)
  {
   Page_Validators[i].enabled = status;
   Page_Validators[i].style.display = status ? 'inline' : 'none';      
  } 
 }
 else 
 { 
  //this is a way to check that the control is a validation control
  if(control.controltovalidate != null)
  {
   control.enabled = status;
   control.style.display = status ? 'inline' : 'none';  
  }
  for( var i=0; i < control.childNodes.length; i++)
  {
   traverseTree(status, control.childNodes[i]);
  }
 } 
}

What this function does is the following: If the control is null (in other words if a container control is provided), the easiest way to set the status of all the validators would be to loop through the Page_Validators array. This array is generated whenever validation is used in a page. To set the status of a validator, we set its enabled property to status (which is either true or false), and we hide/show the validator by setting its style.display to none or inline. Now, if the container is provided (control != null), then we traverse the control tree recursively, setting the status of all validators on our way. How do we know that a certain control is a validation control? By checking its evaluationfunction attribute.

Now, this is how we enable validators inside a container:

JavaScript
function enableValidators(containerID)
{
 var control;
 if(containerID == null)
 {
  control = null;     
 }
 else
 {
  control = document.getElementById(containerID);  
 } 
 if( containerID == null || control != null )
  traverseTree(true,  control); 
}

This function checks if a containerID is provided; if it is, then the traversTree function is called with the corresponding control found by using getElementById. The disableValidators function is similar.

Now, here we can see the traverse function for the ControlToValidate functions:

JavaScript
function traverseTreeCTV(status, controlToValidateID, control)
{
  if(control == null)
  {
    for(var i = 0; i < Page_Validators.length; i++)
    {
      if(Page_Validators[i].controltovalidate != null &&
        Page_Validators[i].controltovalidate == controlToValidateID)
      {
        Page_Validators[i].enabled = status;//disable validator
        Page_Validators[i].style.display = status ? 'inline' : 'none';
      }
    }
  }
  else
  {
    if(control.controltovalidate != null &&
      control.controltovalidate == controlToValidateID)
    {
      control.enabled = status;//disable validator
      control.style.display = status ? 'inline' : 'none';
    }
    for( var i=0; i < control.childNodes.length; i++)
    {
      traverseTreeCTV(status, controlToValidateID, control.childNodes[i]);
    }
  }
}

If a container control is not provided, then the status of all the controls in the page that validate the control of ID controlToValidateID is set. Like before, we loop through the Page_Validators array. If the container is provided, then we traverse the control tree recursively, setting the status of all controls that have a controltovalidate of controlToValidateID.

Nothing new about enableCTVValidators and disableCTVValidators, they just call the above function.

Now, for the Group Validators functions:

JavaScript
function setGroupValidatorsStatus(groupID, status)
{
  for(var i = 0; i < Page_Validators.length; i++)
  {
    if(Page_Validators[i].attributes['groupID'].value == groupID)
    {
      Page_Validators[i].enabled = status;
      Page_Validators[i].style.display = status ? 'inline' : 'none';
    }
  }
}

All the previous function does is look for all the validators that have an attribute called groupID of value groupID. When such controls are found, their status is set accordingly.

Again, enableGroupValidators and disableGroupValidators merely call the above function.

I will leave the Show/Hide functions for you to investigate.

About the Demo Project

The demo provides examples for using most of the provided functions. Inside the project, there is a Web Form called 'WebForm1' and it imports the JavaScript file 'ValidationDefeater.js'.

Inside 'WebForm1', there is a collection of TextBoxes with their corresponding Validators and the buttons to submit the form. These are divided into two sections: one section for Members and the other section for New Users. Logically, the two sections are separate, but functionally, their validators are not, at least without our method. By using the techniques described, they become really two separate sections.

There is a dropdown called ddlMode and it is used to select the mode in which our separation is to be enforced. The modes are: Group mode, Container mode, ControlToValidate mode, and Show/Hide mode.

When the ControlToValidate mode is selected, two new dropdowns appear. Each belonging to one of the two sections, and each holding the names of all the TextBoxes in the corresponding section. The point is to select the name of the control that we wish to disable validation on.

The two btnLogin and btnSubmit buttons each belonging to the corresponding section are prepared in the code-behind. The client side onclick event for these buttons is set to the appropriate function calls according to the selected mode.

When the Show/Hide mode is selected, two RadioButtons appear. Selecting one of these two will show a section (disabling all the validation inside it) and show the other (enabling all the validation inside it).

That wraps it all up.

Finally

I hope what I provided helps most of the readers. Please feel free to comment and provide suggestions or alternatives that will help improve. If you have appreciation for this article, show it by voting. Thank you.

Updates

  • 17 May 2006:
    • Made some modifications to the demo code.
    • evaluationfunction is now used instead of controltovalidate to check for validators.
    • Now the validation is re-enabled after the buttons are clicked (onblur).
    • Added a section "Server Side Validation".

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Lebanon Lebanon
Over 5 years of experience as a Web Developer using ASP.NET.
Appreciates Good Design and continually seeks to improve his methods.

MCP in Developing Web Applications using ASP.NET, and in XML Web Services and Server Components.

Comments and Discussions

 
QuestionValidation with gridview and Validation summary Pin
JL. ROBERT19-Jul-07 5:05
JL. ROBERT19-Jul-07 5:05 
GeneralIn ASP.NET 2.0 Pin
Amit K Bhagat5-Jun-07 12:18
Amit K Bhagat5-Jun-07 12:18 
GeneralGroup Validation Pin
Thrill517-Oct-06 9:40
Thrill517-Oct-06 9:40 
GeneralIssues and improvements Pin
Peter Blum16-May-06 1:52
Peter Blum16-May-06 1:52 
GeneralRe: Issues and improvements Pin
M. Shehabeddeen17-May-06 0:25
M. Shehabeddeen17-May-06 0:25 
GeneralRe: Issues and improvements Pin
yan194546-Jul-07 3:14
yan194546-Jul-07 3:14 
I have frame 1.1. While I down loaded the code and builded all the dropdown box ddlControlsMember.Selectedvalue is not working. I replaced with property SelectedItem.Value. For our validation control ;
groupID and DESIGNTIMEDRAGDROP in the html are red. I ran the application. it did not work as the article stated. validation in group. I do not know why .

I have visual studio 2002. The solution file is not working. I created my new file and add the existed item to my project.

Thx you for the inside.

Frances

GeneralRe: Issues and improvements Pin
M. Shehabeddeen8-Jul-07 6:11
M. Shehabeddeen8-Jul-07 6:11 
GeneralNice work Pin
Adam Tibi15-May-06 1:59
professionalAdam Tibi15-May-06 1:59 
GeneralRe: Nice work Pin
M. Shehabeddeen15-May-06 8:03
M. Shehabeddeen15-May-06 8:03 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.