Sunday, 4 March 2012

How to 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 occur instantly on Client Side based on the state of one CheckBox control and not after a full page PostBack.
For example imagine you have TextBox control that needs to be filled by user only if one CheckBox control on the page is checked.
So normally, you would add RequiredFieldValidator to the page, wire it up with that TextBox control, and enable/disable this Validator on PageLoad 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 the page. On PageLoad the RequiredFieldValidator gets activated, and page is presented to the user again with validation error.
User changes his mind and makes Checkbox unchecked (he does not want to fill the TextBox) and tries to submit the form, but what happens?
Client Side validation of RequiredFieldValidator is triggered to enforce user to fill that TextBox and user cannot submit the page.
The only solution is to Enable/Disable the ASP.NET Validator controls on page with JavaScript code as soon as user 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)
Takes a client-validator and a Boolean value. Enables or disables a client validator. Being disabled will stop it from evaluating and it will always appear valid.
ValidatorHookupControl(control, val)
Takes an input HTML element and a client-validator. Modifies or creates the element's change event so that it updates the validator when changed. This can be useful for custom validators that depend on multiple input values.
 NOTE:
One thing is important to say here: Server Side Validation will occur after page PostBack even if you programmatically disable Client Side validation with Java Script.
This API just allows you to manipulate the Client Side state of your Validator controls, Disable or Enable them and therefore allow or forbid the user to submit the page, and all this does not affect how this Server Side Validators will behave on Server Side.
So how we use that API?

Let us set up a simple example project with two TextBox controls (Full Name and Email) with RequiredFieldValidators for both of them and RegularExpressionValidator for Email field and a CheckBox control that Enables/Disables the Client Side validation for all the Validator controls.

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%>' to dynamically retrieve the Client Side names of our Server Side Validators so we don't have to hard code them, and therefore have to change 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 a PostBack and display status messages in the Label control depending on the validation status of the page/validation controls.
So let us see what happens if we run the sample page? Initially Client Side validation is enabled for all our Validator controls and until we fill the required data we cannot submit the page:

Description: http://www.aspdotnetfaq.com/userfiles/image/FaqFiles/control-validator-controls-client-side-validation/ValidatorsEnabled.jpg
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 not submitted, instead an error message is displayed in each Validator control and in Validation Summary control on the bottom of the page:

Description: http://www.aspdotnetfaq.com/userfiles/image/FaqFiles/control-validator-controls-client-side-validation/validatorsEnabledError.jpg
Now, if you click on the CheckBox on top and uncheck it, the Client Side validation for all our Validator controls will be instantly disabled by calling our Java Script function ValidatorsEnabled(false) and all the validation errors will at once dissapear!
You will be permitted to submit the page, even if you dont fill in the required information, full page PostBack will happen and on the Server Side validation will get triggered for each Validator control.
Good side of this is that you can override the Validators behaviour on Client Side and allow the Post Back to occur and then decide on Server Side if you really want to disable 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 Side validation and submitted it without filling all the required data:

Description: http://www.aspdotnetfaq.com/userfiles/image/FaqFiles/control-validator-controls-client-side-validation/ValidatorsDisabled.jpg
TIP:
Always make sure you have a really good reason to do all this because generally Client Side validation is a good thing and should be enabled by default and used whenever possible because 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 :