Introduction
With ASP.NET 2.0, we got a new 'ValidationGroup
' property on validators as well as controls. This property enables us to group together certain controls and their respective validators under one common group. On page submit, we can tell the runtime which ValidationGroup
to consider and ignore the rest. By using a ValidationGroup
, we can avoid having to manually enable/disable validations. But there's a small problem -- only one ValidationGroup
can be specified during submit. This article shows a trick to work with multiple ValidationGroup
s on the client-side during page submit.
Background
To begin with, I have four ValidationGroup
s, out of which three are active at any given point of time, during page-submit. Whenever the validation fails on any control, the background color of the control becomes red.
The example consists of an ASPX page which calls a UserControl. This example can be easily extended to any number of ValidationGroup
s in any number of UserControls.
First, the User Control -- I have a DropDownList
in the UserControl which sets up a criteria for conditional validation. By "conditional validation", I mean a particular ValidationGroup
is ignored in the Page_ClientValidate()
call based on what the user has selected in the DropDownList
.
Broadly, there are two sets of ValidationGroup
s, namely ValidationGroup="ValSumm1"
and ValidationGroup="ValSumm9"
. So if ValidationGroup="ValSumm1"
is active, then ValidationGroup="ValSumm9"
is ignored, and vice-versa. There is also a third ValidationGroup
in the UserControl on the DropDownList
: ValidationGroup="ValSummG"
-- to make sure that the user selects a criteria.
Listing 1: UserControl markup
<asp:DropDownList ID="ddl1" runat="server" AppendDataBoundItems="true">
<asp:ListItem Text="Select Validation Group" Value=""></asp:ListItem>
<asp:ListItem Text="ValSumm1" Value="bb"></asp:ListItem>
<asp:ListItem Text="ValSumm9" Value="cc"></asp:ListItem>
</asp:DropDownList>
<asp:RequiredFieldValidator ID="RequiredFieldValidator2"
runat="server" ControlToValidate="ddl1"
ErrorMessage="ValGroup is required."
Text="ValGroup is required"
VALIDATIONGROUP="VALSUMMG">
</asp:RequiredFieldValidator>
<asp:TextBox ID="txt1" runat="server" ></asp:TextBox>
<asp:RequiredFieldValidator ID="Req1" runat="server"
ControlToValidate="txt1" ErrorMessage="Text1 is required."
Text="Text1 is required"
VALIDATIONGROUP="VALSUMM1"></asp:RequiredFieldValidator>
<asp:DropDownList ID="ddl2" runat="server"
AppendDataBoundItems="true" >
<asp:ListItem Value="">Select Item</asp:ListItem>
<asp:ListItem Value="1" Text="1"></asp:ListItem>
<asp:ListItem Value="2" Text="2"></asp:ListItem>
</asp:DropDownList>
<asp:RequiredFieldValidator ID="Req4" runat="server"
ControlToValidate="ddl2" ErrorMessage="Item is required."
Text="Item is required" VALIDATIONGROUP="VALSUMM1">
</asp:RequiredFieldValidator>
</fieldset>
<asp:TextBox ID="TextBox1" runat="server"
VALIDATIONGROUP="VALSUMM9" ></asp:TextBox>
<asp:RequiredFieldValidator ID="Req2" runat="server"
ControlToValidate="TextBox1" ErrorMessage="Text2 is required."
Text="Text2 is required." VALIDATIONGROUP="VALSUMM9">
</asp:RequiredFieldValidator>
<asp:TextBox ID="TextBox2" runat="server"
VALIDATIONGROUP="VALSUMM9"></asp:TextBox>
<asp:RequiredFieldValidator ID="Req3" runat="server"
ErrorMessage="Text3 is required." ForeColor="Red"
ControlToValidate="TextBox2"
Text="Text3 is required." VALIDATIONGROUP="VALSUMM9">
</asp:RequiredFieldValidator>
The parent ASPX page has a ValidationSummary
for the complete app, a ValidationGroup
: ValidationGroup="ValSummP"
. So the parent page and the UserControl together makes it four unique ValidationGroup
s.
Listing 1: ASPX markup
<asp:UpdatePanel ID="UpdatePanel2"
runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:ValidationSummary ID="SUMMARY1" runat="server" />
<fieldset>
<asp:TextBox ID="TextBox1" runat="server" ></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
ControlToValidate="TextBox1" runat="server"
Text="RequiredFieldValidator"
ErrorMessage="RequiredFieldValidator"
VALIDATIONGROUP="VALSUMMP" >
</asp:RequiredFieldValidator>
<br />
<uc1:ValidationUserControl ID="ValUC" runat="server" /><br /><br />
<asp:Button ID="btn2" runat="server"
Text="Submit2" OnClientClick="return ValidateNow();"
onclick="btn2_Click" />
</fieldset>
</ContentTemplate>
</asp:UpdatePanel>
Currently, I have hardcoded the ValidationGroup
s in the UserControl. So if you are using just a single instance of this control in a page, it won't be a problem. However, we can pass the ValidationGroup
name from the parent calling page to the UserControl and hence make the UserControl's ValidationGroup
name dynamic. The thing to focus here is how to validate a page, client-side as well as server-side, when we have more than one ValidationGroup
running concurrently. Broadly speaking, this whole thing is done in three steps:
- Step 1 -- On the parent page for a given
ValidationGroup
, call the function ValidatorValidate()
passing the relevant ValidationGroup
, which will update the IsValid
property of all validators under that group. Next on the parent page again, call the function fnOnUpdateValidators()
passing the relevant ValidationGroup
, which will set the background color of any control on which validation fails. - Step 2 -- The above two functions are called in the UserControl, for all the active
ValidationGroup
s participating in the current request. - Step 3 -- Finally, in the parent page, set the page level validation status and update the
ValidationSummary
control by the following two calls:
ValidatorUpdateIsValid();
ValidationSummaryOnSubmit();
Now check if the complete page is valid on the client:
if (!Page_IsValid) {
return false;
}
A few things to notice here ---
<script language="javascript" type="text/javascript">
function ValidateNow() {
My_PageClient_Validate("ValSummP");
fnOnUpdateValidators("ValSummP");
abc();
ValidatorUpdateIsValid();
ValidationSummaryOnSubmit();
if (!Page_IsValid) {
return false;
}
return true;
}
function My_PageClient_Validate(CurrValGrp) {
for (i = 0; i < Page_Validators.length; i++) {
var val = Page_Validators[i];
if (val.validationGroup == CurrValGrp) {
ValidatorValidate(Page_Validators[i], CurrValGrp, null);
}
}
}
function fnOnUpdateValidators(CurrValGrp) {
for (var i = 0; i < Page_Validators.length; i++) {
var val = Page_Validators[i];
var ctrl = document.getElementById(val.controltovalidate);
if (ctrl != null && ctrl.style != null) {
if (val.validationGroup == CurrValGrp) {
if (!CheckValidatorsForControl(ctrl)) {
ctrl.style.backgroundColor = 'red';
}
else {
ctrl.style.backgroundColor = '';
}
}
}
}
}
</script>
The main client-side function which sets the validator's IsValid
property is ValidatorValidate(Page_Validators[i], CurrValGrp, null);
.
I run the ValidatorValidate
function for all the relevant ValidationGroup
s which I want.
The My_PageClient_Validate()
function takes the active ValidationGroup
name and basically sets up the IsValid
property of all the validator controls which has this supplied ValidationGroup
. This is a little different from the standard PageClient_Validate
version, in the sense that I make sure the validators fall under the ValidationGroup
I 'm trying to validate so that they do not nullify my earlier validation results. Hence, the ValidatorValidate
call is inside the if
check.
Next is the function fnOnUpdateValidators()
, which basically sets the background color of the control on which the validation failed. The above two steps are repeated in the UserControl too.
So summarily -- I update the validator control's IsValid
property, and based on that, set the background color of the control on which validation failed - first for the parent page, and then the UserControl. Once all the relevant ValidationGroup
s are validated, I set up the page level Page.IsValid
boolean value by calling these two functions:
ValidatorUpdateIsValid();
ValidationSummaryOnSubmit();
Notice the ValidationSummaryOnSubmit()
function, I didn't supply any ValidationGroup
. So it covers all ValidationGroup
s that are currently relevant. On the server side, it's just a Page.IsValid
check.
That's it. The complete source code is attached.
Hope this article helps someone. Thanks for reading.