Art Of Programming

musings by Dmytrii Nagirniak

Client-side CustomValidator - Overcomplicating Things

One more time using WebForms I was struggling because of overcomplicated things.

I just needed to validate client-side using CustomValidator. So what’s a problem? There is a ClientValidationFunction that does exactly this.

The most important problem with this approach: it’s impossible to set ControlToValidate property to controls that don’t have values (there’re plenty of them). It just gives a runtime error.

I could of course write another server control and it would be the best option. But I was lazzy for that and didn’t feel it’s good to write it for simple things.

So I have the problem in my ClientValidationFunction: It doesn’t receive any data except value (that is not available). So I decided to extend this approach and make the validation function to look like this:

function ValidateAgreement(src, args, extParam)
{
if (extParam) {
    args.IsValid = extParam.checked;
}
}

This is just a simple example but shows the idea. We can pass any data via extParam in our validator. So how is it used? Of course we need to get this parameter somewhere.

So the server’s code looks like this:

<asp:CustomValidator id="AgreementValidator" runat="server"
Display="Dynamic"
ClientValidationFunction='<%# string.Format("CVH.createFunction(ValidateAgreement, {0})", Agreement.ClientID) %>' />

What’s happening there? ClientValidationFunction is assigned a method created by CVH.createFunction JavaScript.

What’s CVH.createFunction? Here it is:

// CVH=CustomValidatorHelper
var CVH={
createFunction: function(validationFunction, extParamData) {
    var originalFunction = validationFunction;
    var extParam = extParamData;

    return function(src, args) {
        // Proxy the call...
        return originalFunction(src, args, extParam);
    }
}
}
var CustomValidatorHelper=CVH;
So this just creates a function that becomes a proxy between CustomValidator internals and the actual validation function. This allows to pass more parameters to the validation function.

Other possible usage. Just don’t allow user to submit form if some content is not visible (for example, license agreement has not ben read).

<asp:CustomValidator id="AgreementScrolledDivValidator" runat="server"
ClientValidationFunction="CVH.createFunction(VisibleDivValidator, 'contentDiv')" />
function VisibleDivValidator(src, args, extParam) {
args.IsValid = (!!extParam && document.getElementById(extParam).style.display == 'block');
}

I don’t need anymore to create server controls to validate on the client. And I like this.

It’s a power of JavaScript.

But all the validation stuff is a bit ugly with WebForms. I wish it could use some JS validation framework… Like fValidate, Validation jQuery Plugin.

Comments

Dmytrii Nagirniak
You are welcome.
Nick Pearce
Brilliant. Worked immediately and was easy to expand to three parameters. THANK YOU.
Anonymous
Dude, You are just awesome……….Millions Thanks to you. I have spent more than a day to but couldn’t.

Thanks for this post.
Keep posting……..
Anonymous
This is brilliant! I have been looking for a way to pass extra parameters for hours!
Many thanks, Jeroen
Dmytrii Nagirniak
You can put the JS code wherever you like (I prefer external JS file).

With my approach you’ll need to iterate all checkboxes and return true if there’s one checked.

But in your case You can do this without my approach at all:
First thing you need to do is to determine the number of items checked. You can do it by adding onclick attribute to each CheckBox in the grid, like so:

void GridView_RowDataBound(Object sender, GridViewRowEventArgs e) {
CheckBox check = FindYourCheckBoxInTheRow(sender, e);
if (ckeck != null) {
check.Attributes["onclick"] = string.Format("itemClicked('{0}')", check.ClientID);
}
}

Next, implement your itemClicked JS function like this:
var globalNumberOfItemsChecked = 0;
function itemClicked(id) {
var justChecked = document.getElementById(id).value;

globalNumberOfItemsChecked = justChecked ? globalNumberOfItemsChecked+1 : globalNumberOfItemsChecked-1;
}

Ok. Now we know how many items are checked at any time. So we can just check that in the validator function:
<asp:CustomValidator id="ItemCheckedValidator" runat="server"
Display="Dynamic"
ClientValidationFunction='ValidateItemChecked' />

and:
function ValidateItemChecked(src, args) {
args.IsValid = globalNumberOfItemsChecked > 0;
}

That's it. If I haven't forgotten anything it should work.
Anonymous
Hi,

I have problem with above technique. I want to use the above validation to validate the gridview for selection of at least one checkbox.
I am using external .js file. Should I write createFunction script in aspx page or .js file?

Can u please help me as I am not able to call the client validation function(eg. TestCheckBox)?

Thanks in advance…
Anonymous
Great post!!!! I have searched for this. Helped me a lot.
Dmytrii Nagirniak
Glad you found it helpful.
Anonymous
Awesome!!! I have been searching for something like this all over the web.

Comments