Tuesday, February 16, 2010

Control ASP.NET Validator Controls Client Side validation from JavaScript

Recently I needed to disable some ASP.NET RequiredFieldValidator controls on one page depending on user input.

This is trivial you say. But the problem was that this needed to occurinstantly on Client Side based on the state of one CheckBox control andnot after a full page PostBack.
For example imagine you have TextBoxcontrol that needs to be filled by user only if one CheckBox control onthe page is checked.

So normally, you would add RequiredFieldValidator to the page, wire itup with that TextBox control, and enable/disable this Validator onPageLoad event depending on the Checked state of the CheckBox.
But let us consider this rare situation:User checks the CheckBox, without filling the TextBox and submits thepage. On PageLoad the RequiredFieldValidator gets activated, and pageis presented to the user again with validation error.

User changes his mind and makes Checkbox unchecked (he does not want tofill the TextBox) and tries to submit the form, but what happens?

Client Side validation of RequiredFieldValidator is triggered toenforce user to fill that TextBox and user cannot submit the page.
The only solution is to Enable/Disablethe ASP.NET Validator controls on page with JavaScript code as soon asuser changes the Checked state of the CheckBox control on the page.
After some digging I found out that ASP.NET Validator controls have Client Side API that supports some niffty features, so here is the list of supported Client Side functions:


ValidatorValidate(val)

Takes a client-validator as input. Makes the validator check its input and update its display.

ValidatorEnable(val, enable)

Takesa client-validator and a Boolean value. Enables or disables a clientvalidator. Being disabled will stop it from evaluating and it willalways appear valid.

ValidatorHookupControl(control, val)

Takesan input HTML element and a client-validator. Modifies or creates theelement's change event so that it updates the validator when changed.This can be useful for custom validators that depend on multiple inputvalues.
 NOTE:
One thing is important to say here: ServerSide Validation will occur after page PostBack even if youprogrammatically disable Client Side validation with Java Script.
This API just allows you to manipulatethe Client Side state of your Validator controls, Disable or Enablethem and therefore allow or forbid the user to submit the page, and allthis does not affect how this Server Side Validators will behave onServer Side.
So how we use that API?



Let us set up a simple example project with two TextBox controls (FullName and Email) with RequiredFieldValidators for both of them andRegularExpressionValidator for Email field and a CheckBox control thatEnables/Disables the Client Side validation for all the Validatorcontrols.



Here is how our ASPX page code looks like:

 
<body onload="InitValidators();">
    <form id="form1" runat="server">
    <div>
        <asp:CheckBox ID="enableValidatorsCheckBox" runat="server" Text="Validators Enabled - Click on this checkbox to Enable/Disable client side validation for ASP.NET Validator controls." Checked="true" onclick="ValidatorsEnabled(this.checked);" />
        <br /><br />
        <asp:Label ID="Label1" runat="server" Text="Full Name"></asp:Label>&nbsp;
        <asp:TextBox ID="Name" runat="server"></asp:TextBox>
        <asp:RequiredFieldValidator ID="NameRequiredFieldValidator" runat="server" ControlToValidate="Name"
            ErrorMessage="Please enter your full name"></asp:RequiredFieldValidator>
        <br />
        <asp:Label ID="Label2" runat="server" Text="Email"></asp:Label>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
        <asp:TextBox ID="Email" runat="server"></asp:TextBox>
        <asp:RequiredFieldValidator ID="EmailRequiredFieldValidator" runat="server" ControlToValidate="Email"
        ErrorMessage="Please enter your email address."></asp:RequiredFieldValidator>
        <asp:RegularExpressionValidator ID="EmailRegexValidator" runat="server"  ControlToValidate="Email"
        ErrorMessage="Invalid Email" ValidationExpression=".*@.{2,}\..{2,}"></asp:RegularExpressionValidator>
        <br /><br />
        <asp:Button ID="SubmitButton" runat="server" Text="Submit" />   
        <br /><br />
        <asp:Label ID="MessagesLabel" runat="server" Text=""></asp:Label> <br />
        <br />
        <asp:ValidationSummary ID="ValidationSummaryControl" runat="server"
            HeaderText="Validation Errors:" /> 
    </div>
    </form>
    <script type="text/javascript" language="javascript">
        function InitValidators()
        {
            // retrieve instance of our checkbox
            var checkbox = document.getElementById('<%=enableValidatorsCheckBox.ClientID%>');
            // enable/disable all validators on page based on checkbox state
            ValidatorsEnabled(checkbox.checked);
        }

        function ValidatorsEnabled(state)
        {
            ValidatorEnable(document.getElementById('<%=NameRequiredFieldValidator.ClientID%>'), state);
           ValidatorEnable(document.getElementById('<%=EmailRequiredFieldValidator.ClientID%>'), state);                                   
            ValidatorEnable(document.getElementById('<%=EmailRegexValidator.ClientID%>'), state);           
        }
    </script>
</body>


So as you can see from the code we have created a simple helper Java Script function ValidatorsEnabled(state) to enable/disable all validator controls on the page depending on the state parameter supplied.



On each page load (using the body onload Client Side event) we call the InitValidators() function that just takes the Checked state of the CheckBox control and calls the ValidatorsEnabled with that value so that Client Side validation is enabled/disabled on page load.
Also whenever user clicks on the CheckBox control (using the onclick Client Side event) we call the ValidatorsEnabled function also supplying the state of the CheckBox as state parameter to Enable/Disable Client Side validation.
Note: we are using Server Side tags in our JavaScript code: '<%=NameRequiredFieldValidator.ClientID%>' todynamically retrieve the Client Side names of our Server SideValidators so we don't have to hard code them, and therefore have tochange them in Java Script code if we change their names on Server Side.



And here is what happens at our code behind:

 
    protected void Page_Load(object sender, EventArgs e)
    {
        if (Page.IsPostBack)
        {
            Page.Validate();

            StringBuilder msg = new StringBuilder("Page Is Submitted. Validation State: ");

            if (Page.IsValid)
            {
                msg.AppendFormat("Valid. Submitted Name: {0}  Submitted Email: {1}", Name.Text, Email.Text);
            }
            else
            {
                msg.Append("INVALID!");
            }

            MessagesLabel.Text = msg.ToString();
        }
    }


Simple stuff here, we just trigger the page Validation if there is aPostBack and display status messages in the Label control depending onthe validation status of the page/validation controls.
So let us see what happens if we runthe sample page? Initially Client Side validation is enabled for allour Validator controls and until we fill the required data we cannotsubmit the page:





If you try to submit this page Post Back will not occur because Client Side validation will get triggered.
Here is the result, page is notsubmitted, instead an error message is displayed in each Validatorcontrol and in Validation Summary control on the bottom of the page:





Now, if you click on the CheckBox on topand uncheck it, the Client Side validation for all our Validatorcontrols will be instantly disabled by calling our Java Script functionValidatorsEnabled(false) and all the validation errors will at once dissapear!
You will be permitted to submit thepage, even if you dont fill in the required information, full pagePostBack will happen and on the Server Side validation will gettriggered for each Validator control.

Good side of this is that you canoverride the Validators behaviour on Client Side and allow the PostBack to occur and then decide on Server Side if you really want todisable some of the Validator Controls or display error messages,enforce custom business logic etc.


Here is how the page looks after you have disabled Client Sidevalidation and submitted it without filling all the required data:




TIP:
Always make sure you have a really goodreason to do all this because generally Client Side validation is agood thing and should be enabled by default and used whenever possiblebecause it saves bandwidth and forbids unnecessary postbacks.



Control is now in your hands, so use it wisely :)



Sample Visual Studio WebSite Code Download

No comments: