How to skin all ASP.Net validators? - asp.net

I want all of the validators in an ASP.Net 3.5 website to have a CssClass value of "error". My initial thought was to do this in a theme skin like so:
<asp:CompareValidator runat="server"
CssClass="error" />
<asp:CustomValidator runat="server"
CssClass="error" />
<asp:RequiredFieldValidator runat="server"
CssClass="error" />
<belCommon:ZipCodeValidator runat="server"
CssClass="error" />
<belCommon:PhoneNumberValidator runat="server"
CssClass="error" />
This is only a partial listing of validators that I use. Ideally, I would like to do something like this:
<asp:BaseValidator runat="server"
CssClass="error" />
And because all validators inherit from BaseValidator, I would expect that this would work, but it doesn't. Is there a way to accomplish this without adding every single validator control to the skin explicitly?
Update:
I found a different approach using javascript:
Sys.Application.add_init(function(sender, args)
{
if (Page_Validators != null)
{
for (i = 0; i < Page_Validators.length; i++)
{
Page_Validators[i].className = "error";
}
}
});
ASP.Net generates a javascript variable called Page_Validators, which is an array of the validation spans. This script checks to see if it exists and then loops through and sets the class name. I added this to the master page and its working so far.

Not that I am aware of, when defining a skin you are specifically working with individual controls and you don't have a way of specifying it any other way, as it matches based on the tags used.
From the looks of it though, you are creating your own custom validators as well, you might modify your controls to have a default cssclass of error to save a bit of time.

I'd be tempted to iterate over the controls of the page in the server pageload method and to apply the css class there:
foreach (object obj in this.Controls)
{
if (obj is BaseValidator)
{
((BaseValidator)obj).CssClass = "error";
}
}
This may not be the best way to do this and I've not had the opportunity to test it but hopefully it might help you along the way.

I found a different approach using javascript:
Sys.Application.add_init(function(sender, args)
{
if (Page_Validators != null)
{
for (i = 0; i < Page_Validators.length; i++)
{
Page_Validators[i].className = "error";
}
}
});
ASP.Net generates a javascript variable called Page_Validators, which is an array of the validation spans. This script checks to see if it exists and then loops through and sets the class name. I added this to the master page and its working so far.

Related

Validators / Controls will be executed always even a condition is false

I'm experienced in developing with ASP.NET MVC but have to deal with a lagacy web application with web forms.
I have an html form and inside, there are several input fields and validators (<asp:TextBox />, <asp:CustomValidator />, <ajax:MaskedEditValidator />).
The second part of the form should only be rendered / visible if a condition resolves to true. Also the associated validators inside this block should only validate if a given condition resolves to true. For this I wrapped the respective part in a condition block:
<%
if (condition)
{
%>
...
<ajax:MaskedEditExtender runat="server" ID="meePreisProGruppe" TargetControlID="PreisProGruppeInsertTextBox"
Mask="999" MessageValidatorTip="true" OnFocusCssClass="MaskedEditFocus"
OnInvalidCssClass="MaskedEditError" MaskType="Number" InputDirection="RightToLeft"
AutoComplete="false" ErrorTooltipEnabled="True" />
<ajax:MaskedEditValidator ID="mevPreisProGruppe" runat="server" ValidationGroup="vgBuchungsanfrageMP"
ControlExtender="meePreisProGruppe" ControlToValidate="PreisProGruppeInsertTextBox" IsValidEmpty="false"
InvalidValueMessage="Preis p.Gruppe ungültig" emptyvaluemessage="Preis p.Gruppe fehlt" EmptyValueBlurredText='<img src="/bsb/img/srf/icon_exclamation_error.gif">'
InvalidValueBlurredMessage='<img src="/bsb/img/srf/icon_exclamation_error.gif">'
Display="Dynamic" />
...
<asp:CustomValidator ID="cvRechnungsadresse" Display="Dynamic" ErrorMessage="Rechnungsadresse nicht vollständig!"
OnServerValidate="ServerValidationRechnungsadresse" ValidationGroup="vgBuchungsanfrageMP"
runat="server" />
...
<%
}
%>
With this, the controls do not get rendered, this is what I want. But all the validators will be executed independent to what the condition resolve, though.
How can I solve this issue?
My answer below is based on the assumption that the condition for validators to evaluate is different from the condition for the input control/validators to be rendered.
There is a standard JavaScript function called ValidatorValidate when you use validation in web forms. You need to override this using sample code like below to implement your requirement.
An important point to keep in mind with this solution is to place the code below just before the closing body tag so the function being overridden has been already loaded in browser else you might get a JavaScript error saying that window.ValidatorValidate is undefined.
Also, implement same requirement on server-side using the C# code below, since validators are evaluated on client-side as well as server-side.
Override ValidatorValidate function in JavaScript
<script type="text/javascript">
//create a condition in JavaScript for your validators to validate
//make condition a global variable, like here ( don't set it inside a function)
var condition = ...; //write your condition code on right side of equal operator
//populate this array with client ID's of all validators for which you want to conditionally validate
var conditionalValidatorIds = [];
conditionalValidatorIds.push("<%= validator1.CleintID%>";
conditionalValidatorIds.push("<%= validator2.CleintID%>";
conditionalValidatorIds.push("<%= validator5.CleintID%>";
//now override the standard ValidatorValidate function
var originalValidatorValidate = window.ValidatorValidate;
window.ValidatorValidate = function (val, validationGroup, event) {
//check if the condition is true and if yes then skip this function for all
//validators within the conditionalValidatorIds array
if(condition === true) {
for(var i=0; i < conditionalValidatorIds.length; i++) {
if( val.id === conditionalValidatorIds[i] ) {
val.isvalid = true;
ValidatorUpdateDisplay(val);
return;
}
}
}
//perform original validation when condition is false
window.originalValidatorValidate(val, validationGroup, event);
}
</script>
C# code to override validators evaluation on server-side
public override void Validate(string validationGroup)
{
//you will need to define yourCondition on server-side
bool enableValidators = (someCondition === true);
//then enable/disable your validators based on above condition
validator1.Enabled = enableValidators;
validator2.Enabled = enableValidators
validator3.Enabled = enableValidators;
base.Validate(validationGroup);
}
Another option instead of using above approach is to define only custom validators ( no standard validators like requiredfieldvalidator or comparevalidator etc.) within the if condition block and then within each custom validator client-side function, just check for the condition and if its true then set args.IsValid = true; in it. Do the same on server-side events you have for these custom validators.

Is it possible to add logic to influence the way RequiredFieldValidator behaves?

I have added textbox on the page that Jquery to create a datepicker. The problem is that, the textbox doesn't hold the value after a postback. After researching, I found the following solution which works perfectly, i.e. the textbox keeps its value after a postback.
<th>
<asp:CustomValidator ID="customStartDate" runat="server"
ErrorMessage="Start Date" Display = "None" ControlToValidate = "txtStartDate"
ValidationGroup ="HireGroup" ClientValidationFunction ="StartDate_Validate"/>
Start Date:
</th>
<td>
<asp:TextBox ID="txtStartDate" runat="server" Width = "140" ReadOnly = "true"
TabIndex = "5" CssClass = "datepicker" ></asp:TextBox>
<asp:HiddenField ID="hfDatePicker" runat="server"/>
</td>
And this is the Jquery code
//Set datePicker
function SetUpDatePicker() {
var $allDatepickers = $('.datepicker');
$.each($allDatepickers, function () {
$(this).datepicker({
showOn: "button",
buttonImage: "Images/calendar.gif",
buttonImageOnly: true,
minDate: 1,
altField: '[id*="hfDatePicker"]'
});
var $hfDatePicker = $('[id*="hfDatePicker"]');
var val = $($hfDatePicker).attr('Value');
$(this).val(val);
var len = $($hfDatePicker).attr('Value').length;
if (len > 0) {
$(this).datepicker("setDate", new Date($($hfDatePicker).attr("Value")));
}
});
}
Now I have a different type of problem. I can't use a RequiredFieldValidator for a HiddenField as I am getting an error "Hidden Field cannot be validate".
I'm tryind a CustomValidator, but the problem is that this control does acts only when the ControlToValidate is not empty.
I've checked all the property for RequiredFieldValidator and don't see something like ClientValidationFunction property.
Any suggestion on how to solve that problem?
(Based on the comment by #Richard77, I will make this an actual answer.)
You have a several options...
Instead of using a <asp:Hidden>, use a normal <asp:TextBox> but hide it using style='display:none; attribute. This will allow you to use the <asp:RequiredFieldValidator> as per your needs.
Another way to do it is using the <asp:CustomValidator> and add the ValidateEmptyText='true' attribute. This will force the validator to run the code even when the TextBox is empty.
Update - after thinking about this, I would NOT recommend the following, because it's not possible (that I can think of) to override the server-side version of the function, and therefore will leave you open to vulnerabilities. It's fine to do if you're purely using it for say visual reasons, and don't need the actual data to be checked on the server - however, this is an unusual situation.
A final option (but not one that I would necessarily recommend) is to override the function generated by ASP.NET. This would need to be placed on your page somewhere after the script link generated by ASP.NET, something like...
function RequiredFieldValidatorEvaluateIsValid(val) {
if(val.controltovalidate=="myValidatorId"){
// your coding here
} else {
return (ValidatorTrim(ValidatorGetValue(val.controltovalidate)) != ValidatorTrim(val.initialvalue))
}
}

Required field validator issue for multiple controls

In my aspx page in a submission form i have following html.
<p><asp:CheckBox ID="chkWishToDonateFrmTrust " runat="server" onclick="chkWishToDonateFrmTrustHandle(this)" />
Wish to donate from following Trust for future transactions</p><p> </p><p><textarea name="textarea" cols="45" rows="5" class="txtTrustDetails" runat="server"
id="txtTrustDetails" ></textarea></p>
I need to have a required field validation control to validate txtTrustDetails text area only if chkWishToDonateFrmTrust is checked by the user without server post backs for this.only javascript library I am using is Microsoft Ajax Framework.I also have to include this to validation group in form with some other for controls.I already know as my knowledge one required field validator control can only validate single UI control(asp.net forum thread) does anyone in community dealt with this kind of issue in intuitive way?
As another answer has said, use a Custom Validator and do something like this (not tested so may not be quite right...):
<script type="text/javascript">
function validate(sender, args) {
var checkBox = document.getElementById('<%=CheckBox1.ClientID %>');
var textBox = document.getElementById('<%=TextBox1.ClientID %>');
if (checkBox.checked == 1) {
if (textBox.value == '') {
args.IsValid = false;
} else { args.IsValid = true; }
}
}
</script>
<asp:CheckBox ID="CheckBox1" runat="server" />
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:CustomValidator ID="CustomValidator1" ControlToValidate="TextBox1" runat="server"
ErrorMessage="CustomValidator" ClientValidationFunction="validate"></asp:CustomValidator>
Use the custom validator and use the clientValidationfunction to call a javascript function to check your values.
You should also have a servervalidate function incase javascript is off.
you can use a js function or a jquery function to do this is a sample code of how to achieve this
function chkValidate()
{
if($("#chkWishToDonateFrmTrust ").checked)
{
if($("#txtTrustDetails").val()=='')
{
args.IsValid = false;
//your custom message according to you
}
}
}
call this function on your sumbit button onclick;

server side validation in asp.net?

hi all as i know that asp.net provide server side validation control which has there own built-in logic, so i want to ask here can we extend built-in logic, i means suppose we use compare validator for comparing two file at this point it will validate according to there built-in logic, but i want to add some code for compare validator, is this possible.
According to my knowledge in asp.net every control treated as class which has data and code so according to inheritance or extend can we add some code in validation control ?
It looks like you need to use
CustomValidator
You can use a custom function to define when your control passes your validation. In this case could be something like this.
void ServerValidation (object source, ServerValidateEventArgs args)
{
args.IsValid = //Define your validation here
}
CustomValidator is one option. If you rather going to implement validator similar to existing one, you can simply derive from it and override all necessary methods. But the most important method you should look for is the EvaluateIsValid.
A CustomValidator is better in situations when your logic is more likely unique. In case you want to use the logic in multiple places, I would recommend to use inheritance. It allows you to encapsulate the logic in class library if you want, CustomValidator doesn't.
In your markup:
<asp:TextBox id="Text1" runat="server" />
<asp:CustomValidator id="CustomValidator1"
ControlToValidate="Text1"
Display="Static"
ErrorMessage="Not an even number!"
ForeColor="green"
Font-Names="verdana"
Font-Size="10pt"
OnServerValidate="ServerValidation"
runat="server"/>
<asp:Button id="Button1"
Text="Validate"
OnClick="ValidateBtn_OnClick"
runat="server"/>
In the server side code:
void ValidateBtn_OnClick(object sender, EventArgs e)
{
// Display whether the page passed validation.
if (Page.IsValid)
{
Message.Text = "Page is valid.";
}
else
{
Message.Text = "Page is not valid!";
}
}
void ServerValidation(object source, ServerValidateEventArgs args)
{
try
{
// Test whether the value entered into the text box is even.
int i = int.Parse(args.Value);
args.IsValid = ((i%2) == 0);
}
catch(Exception ex)
{
args.IsValid = false;
}
}
This example is a shortened version of the one found at the documentation page for CustomValidator:
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.customvalidator.aspx
Yes you can. Like Carlos's answer link will tell you. You can put the code in the code behind.(.cs file)

How to set the RowStyle of a GridView row depending on a property of the Object that the row is being bound to

I'm currently using a GridView and I want to set the CssClass for the Row depending on a property of the object that the row is being bound to.
I tried the following but it does not work (see comments):
<asp:GridView id="searchResultsGrid" runat="server" AllowPaging="true" PageSize="20" AutoGenerateColumns="false">
<!-- The following line doesn't work because apparently "Code blocks
aren't allowed in this context: -->
<RowStyle CssClass="<%#IIF(DataBinder.Eval(Container.DataItem,"NeedsAttention","red","") %>
<Columns>
<!--............-->
</Columns>
</asp:GridView>
Now I could simply handle the GridView's RowDataBound event and change the css class of the row there...but I'm trying to keep a clear separation between the UI and the page/business logic layers.
I have no idea how to accomplish this and I'm looking forward to hearing any suggestions.
Thanks,
-Frinny
You cannot do this in declarative markup.
Nearly all of GridView's declarative properties (including GridView.RowStyle) are grid-level settings rather than row-level. Apart from TemplateFields , they are not bound data containers, so they don't have access to the data in their rows.
If you want to keep this logic in the .aspx template, your only real option is to use template fields and manipulate their contents:
<asp:TemplateField>
<ItemTemplate>
<span class="<%# ((string)Eval("property3")) == "NeedsAttention" ? "red" : string.Empty %>">
<%# Eval("property1") %>
</span>
</ItemTemplate>
</asp:TemplateField>
Depending on what you want to do, this may be awkward - you don't have access to the containing <td> (or <tr> for that matter) and you'll have to repeat the formatting for each cell.
The GridView class goes to a lot of lengths to hide the details of HTML and styling from you. After all you could create a GridView control adapter that wouldn't even render as HTML tables. (Unlikely though that may be.)
So even though you're trying to avoid it, you're probably best off dealing with this in a OnRowDataBound handler - or use a Repeater (if that's appropriate).
I know it has been almost a year, but if anyone else is trying this, try to subclass the GridView.
public class GridViewCSSRowBindable : GridView
{
public string DataFieldRowCSSClass { get; set; }
protected override void OnRowDataBound(GridViewRowEventArgs e)
{
base.OnRowDataBound(e);
if (!string.IsNullOrEmpty(DataFieldRowCSSClass))
{
//This will throw an exception if the property does not exist on the data item:
string cssClassString = DataBinder.Eval(e.Row.DataItem, DataFieldRowCSSClass) as string;
if (!string.IsNullOrEmpty(cssClassString))
{
string sep = string.IsNullOrEmpty(e.Row.CssClass) ? string.Empty : " ";
e.Row.CssClass += sep + cssClassString;
}
}
}
}
And then in your Page:
<custom:GridViewCSSRowBindable ID="gvExample" runat="server" DataFieldRowCSSClass="RowCSS">
</custom:GridViewCSSRowBindable>
The objects being bound to this example GridView should have a public string RowCSS property.
If you haven't used inherited controls before, you might have to look up how to set that up in your project.
foreach (TableCell gvc in gvRowPhistry.Cells)
{
gvc.ForeColor = System.Drawing.Color.Blue;
}

Resources