Validate Multiple Instances of an ASP.net User Control

metatagsASP.net custom validation with client side JavaScript on multiple instances of a User Control

Problem: You have a page with multiple instances of a User Control that has a form that needs to be validated client side. JavaScript is not calling custom validation on the correct form because of naming conflicts.

In my specific case, I had a User Control that contained a form that we wanted to do multivariate testing on with Google Website Optimizer (GWO). Because we had complex variations that depended on dynamic data we had to work outside of the basic GWO setup. We found a way to optimize the form by including all of  the different variations of the form on the page and allowing GWO to display and hide the different variations. First try resulted in the validation being called on all forms because they all shared the same validation group and ClientID. This is what led me to this solution.

Assumptions: You have a custom validation control on your user control and it is validating server side properly when there is only one instance of the user control on a page.

Solution: Use the codebehind to dynamically generate unique names for the validation function, form field ID and class name, script block and register the JavaScript. Also, generate unique names for the form field class name if you want to use JQuery to find the control with class name ala $(.classname).

Assign the generated JavaScript function name to the custom validator’s ClientValidationFuction property. Lastly, assign the user control’s ClientID to each form field, button, and validator’s ValidatorGroup property.

//Because multiple instances of this form can be added to a page we need to
//insure that our javascript validation is validating the current instance only.

//Register the javascript validation
//We are using a unique script key to indentify this script block. We use this.ClientID
//to get the unique ID for this instance and we use it to make sure the script key,
//javascript function name, class names, //and validation groups are all unique to
//this instance.
if (!this.Page.ClientScript.IsClientScriptBlockRegistered(
    this.ClientID + "script"))
{
StringBuilder script = new StringBuilder();

//Generate unique function name.
//Here the JavaScript is passed the obj being validated and the page arguments
script.Append("function " + this.ClientID + "validatePhoneNumber(obj, args) {\n");

//Generate a unique ID name for the control. JavaScript retrieves the value here.
script.Append("var v = document.getElementById('" + this.ClientID + "_phone').value;\n");

//JavaScript is validating the value and setting args.IsValid true or false accordingly
script.Append("args.IsValid = ((v) && (v.length > 0));\n");
script.Append("}\n");

//Generate unique key for the script block
this.Page.ClientScript.RegisterClientScriptBlock(
    typeof(Page), this.ClientID + "script", script.ToString(), true);
}

//Assign a unique class to the field to be validated
//this is done to access the field in JQuery with $(.classname)
phone.CssClass = this.ClientID + "formphone";

//Assign the Custom Validation Control’s ClientValidationFuction with the
//unique function name we generated in the ClientScript registration
cvPhone.ClientValidationFunction = this.ClientID + "validatePhoneNumber";

//In the aspx page, don't forget to set the Control to Validate property on the validation control.
//Set a unique validation group to distinguish multiple instances of this form.
//This is set on all fields, validation controls, and buttons.
//Now when validation is called it will not call it on other instances.
//This is a lot of coding and there may be a better way.
RequiredFieldValidator1.ValidationGroup = this.ClientID;
name.ValidationGroup = this.ClientID;
cvPhone.ValidationGroup = this.ClientID;
phone.ValidationGroup = this.ClientID;
btnSignUp.ValidationGroup = this.ClientID;

Results: Unique names are properly generated and referenced in JavaScript and validation is triggered on the correct form instance. Validation will not trigger validation on all the form instances because we see unique values to the ValidationGroup.

That’s it. It’s not pretty, but it works. There has to be a better way to do this to cut down on lines of code because this is a maintenance nightmare waiting to happen. I guess if I need this again I will refactor and update this post.

Leave a Reply

    RSS Subscribe to comment feed.