Originally published on my old Charteris blog

I have recently had to create some custom ASP.NET Validators for some CompositeControls that we wrote a couple of month's back. Now I have written plenty of my own validators before so it was not long before I had a class inheriting from BaseValidator.

It was when I was trying to connect my new MyControlValidator to an instance of MyControl on a page that I came across an interesting problem. The control that would hold the value for validation was not my CompositeControl but the TextBox inside it.

In ASP.NET validators are connected to the control they are validating by the ControlToValidate property of the Validator. This is set to the id of the control to be validated. Among many things it is this connection that gets us an id to use for client side validation. The ASP.NET's client side validation is implemented in WebUIValidation.js, in ASP.NET 1.0 this is was physical .js file that was installed as part of ASP.NET, in version 2.0 this changed to become an EmbeddedResource in System.Web.dll. The id will be used in the validating JS to retrieve the control's value for validation and in the case of ASP.NET 2.0 set focus back to the control when it is invalid.

I was trying to lay the foundation for future validators of MyControl so I had to make it work. When I set the ControlToValidate to the id of MyControl the code in WebUIValidation struggled. On the client MyControl is rendered as SPAN element so that is no help. I needed to point the ControlToValidate to the id of the internal TextBox but as a consumer of MyControl I could not get at it. Most examples of Validators with CompositeControls have the Validator embedded in the control. That makes it easy to wire up the Validator but I wanted Validators that could be defined external to MyControl so that simple approach was not enough.

The solution was two-fold, on the server I keep the ControlToValidate pointing at the CompositeControl, that makes it easier for the Validator developer, works well with the server-side validation framework and means I do not have to expose the internals of MyControl. On the client it gets fiddly, the standard JavaScript wants a control to validate that it can get a value from and can set focus to. I decided the best approach was for MyControl to run some script on startup that changes the ControlToValidate on the client to be the id of the internal TextBox. This works well with the validation framework client side and keeps the internals of MyControl within the server and client side implementation of MyControl. This is the client side code to change the controltovalidate .

 

_setValidationTargetToActualControl : function(){
//<summary>For any attached Validators set the controltovalidate on to 
be the internal TextBox</summary>

    
   var timeInputBox_TextBox = this.get_element();
        
   if (timeInputBox_TextBox.Validators){
   for(var validatorIndex = 0;
                               validatorIndex < timeInputBox_TextBox.Validators.length;
                               validatorIndex++){
            
      var validator = timeInputBox_TextBox.Validators[validatorIndex];
                
      // Switch the controltovalidate to be the id of the

      // internal TextBox rather than the containing SPAN

      validator.controltovalidate = timeInputBox_TextBox.id;
   }
}
 

The internal TextBox of MyControl, timeInputBox_TextBox, has easy access its associated validators via the Validators property. This is populated by the standard validation javascript on load.