CustomValidator using CustomValidationScript - asp.net

I have an ASP.NET TextBox with a CustomValidation control that invokes client side validation script.
<asp:TextBox ID="txtSubsContrRbtAmt" runat="server"
CssClass="textEntry NumericInput" Width="150px"
Text="" onKeyUp="SumValues();" MaxLength="16"></asp:TextBox>
<asp:CustomValidator ID="cvalSubsContrRbtAmt" runat="server" ClientValidationFunction="ValidatetxtSubsContrRbtAmt"
ControlToValidate="txtSubsContrRbtAmt" CssClass="errlable" ErrorMessage="Max Decimals = 7"
SetFocusOnError="True" ValidationGroup="CarbsAdd"></asp:CustomValidator>
Here's the Client script:
function ValidatetxtSubsContrRbtAmt(source, args) {
var txtSubsContrRbtAmt = document.getElementById("<%=txtSubsContrRbtAmt.ClientID%>");
var amount = txtSubsContrRbtAmt.value;
args.IsValid = ValidAmount(amount);
if (!args.IsValid)
txtSubsContrRbtAmt.focus();
}
function ValidAmount(amount) {
if (isNumber(amount)) {
return (RoundToXDecimalPlaces(amount, 7) == amount);
}
else {
return true;
}
In the ValidatetxtSubsContrRbtAmt function, the "source" parameter is the CustomValidator. That control has a property "ControlToValidate." If I can get to it, I can programmatically retrieve the value from that control and not have to have a separate function to validate each textbox.
jQuery is too much for me at this point, I'm looking for a plain old Javascript approach, please.

You don't have to get the text box. You can get the value from args.Value. The focus should be set automatically if you set SetFocusOnError="true".
function ValidatetxtSubsContrRbtAmt(source, args) {
var amount = args.Value;
args.IsValid = ValidAmount(amount);
}

You should be able to get to the control from the source object.
function ValidatetxtSubsContrRbtAmt(source, args) {
var controlToFocusOn = source.ControlToValidate;
you can switch that out with "document.getElementByID()" to get the ID or whatever attribute you need
var controlId = document.getElementById(source.ControlToValidate).id;
}
now you can focus or do what you need with the control. I had to access the the actual ControlToValidate earlier today from a CustomValidator.

Related

asp.net - manually run client-side validation code from another event

I want to run whatever client-side validation routine is hooked up to a particular text input element.
The validation has been set up using CustomValidator:
<asp:textbox id="AddEstTime" runat="server" Width="55px"></asp:textbox><br />
<asp:CustomValidator ID="AddEstTimeCustomValidator" ClientValidationFunction="AddEstTimeCustomValidator_ClientValidate" OnServerValidate="AddEstTimeCustomValidator_ServerValidate" ErrorMessage="Please enter a time" ControlToValidate="AddEstTime" runat="server" Display="Dynamic" ValidateEmptyText="true"/>
<asp:CheckBox ID="AddIsTM" runat="server" Text="T&M" />
and the javascript:
function AddEstTimeCustomValidator_ClientValidate(sender, args) {
var checkbox = $("input[id$='IsTM']");
args.IsValid = checkbox.is(":checked") || args.Value.match(/^\d+$/);
}
When the CheckBox "AddIsTM" state changes, I want to revalidate the textbox "AddEstTime", using its hooked-up CustomValidator "AddEstTimeCustomValidator".
I am aware of focus -> add a character refocus -> remove character. I am trying to find a more correct way. New to asp.NET.
After looking through the Microsoft client-side code, I came up with this which seems to work:
// client-side validation of one user-control.
// pass in jquery object with the validation control
function ValidateOneElement(passedValidator) {
if (typeof (Page_Validators) == "undefined") {
return;
}
$.each(Page_Validators, function (index, value) {
if ($(value).attr("id") == passedValidator.attr("id")) {
ValidatorValidate(value, null, null);
}
});
}
This was after examining the Page_ClientValidate function:
function Page_ClientValidate(validationGroup) {
Page_InvalidControlToBeFocused = null;
if (typeof(Page_Validators) == "undefined") {
return true;
}
var i;
for (i = 0; i < Page_Validators.length; i++) {
ValidatorValidate(Page_Validators[i], validationGroup, null);
}
ValidatorUpdateIsValid();
ValidationSummaryOnSubmit(validationGroup);
Page_BlockSubmit = !Page_IsValid;
return Page_IsValid;
}
thx sennett (voted)
i just ran the simplest JS
Page_ClientValidate();
if you have a validation group then is
Page_ClientValidate("validationGroupName")
If you want stick with ASP.NET validators eventually you can abuse Validation Groups, but I think that this approach will give you nothing but trouble. Other option is to use jQuery on the client (nice list) only then you will have to duplicate validation on the server side, or to avoid that call server methods from client validations.

Problem with ControlToValidate in dynamic create validation controls

Hi
I have site with two text boxes and dynamically create validation control. This is code from .aspx file:
<form runat="server">
<asp:TextBox AutoPostBack="true" ID="TextBox1" Text="" runat="server" Width="200px"
OnTextChanged="TextBox1_TextChanged"></asp:TextBox>
<asp:TextBox ID="TextBox2" runat="server" Visible="True" Width="200px"AutoPostBack="true"></asp:TextBox>
<asp:Panel ID="Panel1" runat="server">
</asp:Panel>
<asp:TextBox ID="ValidationTB" runat="server" Visible="true"></asp:TextBox>
</form>
This is my code-behind:
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
if (TextBox2.Visible)
{
if (!String.IsNullOrEmpty(TextBox1.Text) && String.IsNullOrEmpty(TextBox2.Text))
{
RequiredFieldValidator RequiredFieldValidator1 = new RequiredFieldValidator();
RequiredFieldValidator1.Enabled = true;
RequiredFieldValidator1.ErrorMessage = "Second field required";
RequiredFieldValidator1.Display = ValidatorDisplay.Dynamic;
RequiredFieldValidator1.ControlToValidate = "TextBox2";
Panel1.Controls.Add(RequiredFieldValidator1);
RequiredFieldValidator1.Validate();
}
if (!String.IsNullOrEmpty(TextBox2.Text) && String.IsNullOrEmpty(TextBox1.Text))
{
RequiredFieldValidator RequiredFieldValidator1 = new RequiredFieldValidator();
RequiredFieldValidator1.Enabled = true;
RequiredFieldValidator1.ErrorMessage = "First field required";
RequiredFieldValidator1.Display = ValidatorDisplay.Dynamic;
RequiredFieldValidator1.ControlToValidate = "TextBox1";
Panel1.Controls.Add(RequiredFieldValidator1);
RequiredFieldValidator1.Validate();
}
if (!String.IsNullOrEmpty(TextBox2.Text) && !String.IsNullOrEmpty(TextBox1.Text))
{
if (Convert.ToDateTime(TextBox2.Text) < Convert.ToDateTime(TextBox1.Text))
{
ValidationTB.Text = null;
RequiredFieldValidator RequiredFieldValidator1 = new RequiredFieldValidator();
RequiredFieldValidator1.Enabled = true;
RequiredFieldValidator1.ErrorMessage = "Bad range of dates";
RequiredFieldValidator1.Display = ValidatorDisplay.Dynamic;
RequiredFieldValidator1.ControlToValidate = "ValidationTB";
Panel1.Controls.Add(RequiredFieldValidator1);
RequiredFieldValidator1.Validate();
}
}
}
}
protected void TextBox1_TextChanged(object sender, EventArgs e)
{
RegularExpressionValidator RegularExpressionValidator1 = new RegularExpressionValidator();
RegularExpressionValidator1.ValidationExpression = #"^[0-9]{4}-(((0[13578]|(10|12))-(0[1-9]|[1-2][0-9]|3[0-1]))|(02-(0[1-9]|[1-2][0-9]))|((0[469]|11)-(0[1-9]|[1-2][0-9]|30)))$";
RegularExpressionValidator1.Enabled = true;
RegularExpressionValidator1.ErrorMessage = "Bad format of date";
RegularExpressionValidator1.Display = ValidatorDisplay.Dynamic;
if (!String.IsNullOrEmpty(TextBox1.Text))
{
RegularExpressionValidator1.ControlToValidate = "TextBox1";
Panel1.Controls.Add(RegularExpressionValidator1);
RegularExpressionValidator1.Validate();
}
if (!String.IsNullOrEmpty(TextBox2.Text))
{
RegularExpressionValidator1.ControlToValidate = "TextBox2";
Panel1.Controls.Add(RegularExpressionValidator1);
RegularExpressionValidator1.Validate();
}
}
}
TextBox ValidationTB is just to make validate on empty control.
This validation doesn't work, when I try:
1. To first textbox enter for example: 2009-09-09
2. To second textbox enter for example: 2009-10-09
Now, everything is OK.
3. I change my first textbox on for example 2009-12-09
I get error Bad range of dates - it's OK.
4. I correct first textbox on 2009-09-09, message disappear-OK.
5. Again enter to first textbox 2009-12-09 - I don't have error, but it should be.
What strange - in debug mode I can see, that in code:
if (Convert.ToDateTime(TextBox2.Text) < Convert.ToDateTime(TextBox1.Text))
{
ValidationTB.Text = null;
RequiredFieldValidator RequiredFieldValidator1 = new RequiredFieldValidator();
RequiredFieldValidator1.Enabled = true;
RequiredFieldValidator1.ErrorMessage = "Bad range of dates";
RequiredFieldValidator1.Display = ValidatorDisplay.Dynamic;
RequiredFieldValidator1.ControlToValidate = "ValidationTB";
Panel1.Controls.Add(RequiredFieldValidator1);
//In debug window: RequiredFieldValidator1.ControlToValidate = "TextBox2"
RequiredFieldValidator1.Validate();
}
instead of ValidationTB control, RequiredFieldValidator1.ControlToValidate is set to TextBox2 (it isn't empty, so I haven't error message).
Why TextBox2 is set to RequiredFieldValidator1.ControlToValidate instead of ValidationTB textbox and how I could solve this?
Thanks
Regards
It looks like what you are really wanting is a CompareValidator instead of what you are using.
Rewrite your 3rd IF block so that it looks like this:
if (!String.IsNullOrEmpty(TextBox2.Text) && !String.IsNullOrEmpty(TextBox1.Text))
{
Response.Write("Executing Block 3");
ValidationTB.Text = null;
CompareValidator CompareValidator1 = new CompareValidator();
CompareValidator1.Enabled = true;
CompareValidator1.ErrorMessage = "Bad range of dates";
CompareValidator1.Display = ValidatorDisplay.Dynamic;
CompareValidator1.Operator = ValidationCompareOperator.LessThan;
CompareValidator1.Type = ValidationDataType.Date;
CompareValidator1.ControlToCompare = TextBox2.ID;
CompareValidator1.ControlToValidate = TextBox1.ID;
Panel1.Controls.Add(CompareValidator1);
CompareValidator1.Validate();
}
This should give you the desired result.
Now... lets talk about some other things going on here.
First, unless you are just doing this as a proof of concept, then I highly encourage you to use the validators in a standard way. Nothing you are doing here requires that you add these validators in dynamically. Everything you want to accomplish can be achieved by simply adding the validators in the markup.
Second, your Event Handler for the text changed event is probably not going to do what you want. As it stands right now, it will fire too late in the page lifecycle to catch errors before your Page_Load event. Your current code will throw an exception if I enter "Blah" into both of the text boxes because it will attempt to convert those to DateTime types.
Lastly, when assigning ID's of existing controls you should use the ID property of that control instead of the Magic Strings you are using now. In this way you won't have to worry about changing the ID in multiple places if you decide to change it in markup.
Anyway, I hope this helps.
Shot in the dark, but try giving your validator controls IDs. RequiredFieldValidator1.ID = "HelloMyNameIsValidator1";

How to go about validating AJAX cascading drop down lists

I am using the AJAX Cascading drop down list but want to add event validation e.g. the compare validators.
As the cascading drop down list requires the page event validation to be disabled what is the best way to do the validation?
Thanks
Andy
Validation Attempt:
I have tried to use a custom validator which calls a Javascript function but it doesnt seem to be picking up the control. I get the following error Microsoft JScript runtime error: Object required
function ValidateCostCentCat(source, arguments)
{
var countryList = document.getElementById("ddlCategory");
if (null != countryList)
{
var iValue = countryList.options[countryList.selectedIndex].value;
if (iValue == "Select Category")
{
arguments.IsValid = true;
}
else
{
arguments.IsValid = false;
}
}
}
The mark-up for the custom validator is
<asp:CustomValidator ID="valcustCategory" runat="server" CssClass="error" Display="Dynamic" ValidationGroup="DirectHire" ClientValidationFunction="ValidateCostCentCat"
ErrorMessage="Please select a Cost Centre Category from the drop down list provided.">!</asp:CustomValidator>
Read This: http://www.w3schools.com/PHP/php_ajax_database.asp
The example demostrate how to select a
value from a dropdown box sent it via
AJAX and get back the responce!
in the middle you can do all the
Validation that you want!
UPDATED with code just for fun! ;-)
Assuming your select is
<asp:DropDownList ID="CategoryDropDownList" runat="server">
Then you function look like this:
function ValidateCostCentCat(source, arguments)
{
var countryList = document.getElementById("CategoryDropDownList");
if (null != countryList)
{
var iValue = countryList.options[countryList.selectedIndex].value;
if ( iValue == "Select Category" ) {
arguments.IsValid = true;
} else {
arguments.IsValid = false;
}
}
}
This must work as expected!
hope this help!

How to set Page.IsValid in ASP.Net

When the page class property IsValid is read only, how can I set it using my own validation method?
So far all I've been able to do is set this property by calling Page.Validate().
How can I write my own functionality that will change the IsValid property just like Page.Validate()?
You don't set IsValid directly instead you call Validate() method of the Page object. If you have your custom validation methods then you need to use CustomValidator object and set that function in its server side validation property.
<asp:CustomValidator ID="YourValidator" runat="server" SetFocusOnError="true"
ControlToValidate="YourControl"
ClientValidationFunction="YOUR_JAVASCRIPT_FUNCTION"
OnServerValidate="YOUR_SERVER_VALIDATION_FUNCTION" Text="*" />
I know this is old, but, I needed to do something similar, basically forcing the IsValid property to false (don't ask why). Here is what I did basically (what you see here is my proof of concept):
Added this to the .aspx page:
<asp:TextBox ID="txtDummy" runat="server" Visible="false" />
<asp:RangeValidator ID="rvDummy" ControlToValidate="txtDummy" runat="server" MinimumValue="1" MaximumValue="2" />
And then I added this to the code behind:
bool makeMyPageInvalid = true;
if (makeMyPageInvalid)
txtDummy.Text = "0";
Page.Validate();
if (Page.IsValid)
ScriptManager.RegisterStartupScript(Page, Page.GetType(), "test", "alert('valid');", true);
else
ScriptManager.RegisterStartupScript(Page, Page.GetType(), "test", "alert('not valid');", true);
You can see that this only allows you to force the page validation to an invalid state. You can use any validator or reason to set this. Hope this helps someone!
The IsValid property is read-only because it is intended for use with server and client-side validators like the RequiredFieldValidator and RegularExpressionValidator. It's read-only because you can't force a page to be valid programmatically. "Valid" in this context means all the validators on the page evaluate to true.
If you feel like using some JavaScript you can do it in the client-side by modifying the variable Page_IsValid like this:
function pageLoad() {
Page_IsValid = false;
}
I use this just in case someone clicks the submit button w/o entering data. Then I can display an alert like this:
function valid() {
if (!Page_IsValid) {
alert("Some Questions Remain Unanswered and are Marked with a Red Asterisc. ( * )");
}
(at the beginning I thought 'who would submit a form w/o data' but sooner rather than later I realized it happens)
This is a really old question, but it came up in a search so I thought I'd add my answer to it. First, create an extension method in one of your helper classes.
public static IEnumerable<T> GetAllControlsOfType<T>(this Control parent) where T : Control
{
var result = new List<T>();
foreach (Control control in parent.Controls)
{
if (control is T)
{
result.Add((T)control);
}
if (control.HasControls())
{
result.AddRange(control.GetAllControlsOfType<T>());
}
}
return result;
}
Now in your code behind file, loop over every validator on the page that is not validating.
foreach (var validator in Page.GetAllControlsOfType<BaseValidator>().Where(w => !w.IsValid))
{
validator.IsValid = true;
}

Elegant way to make CustomValidator work with ValidationSummary messagebox

I have run into this problem before but never quite solved it. I have a form with several validators and also a CustomValidator.
<asp:Label ID="lblMemberNum" runat="server" Text="Membership #:" CssClass="LabelMedium" ></asp:Label>
<asp:TextBox ID="txtMemberNum" runat="server" CssClass="TextBox" ></asp:TextBox>
<asp:RequiredFieldValidator ID="rfvMemberNum" SetFocusOnError="True" runat="server"
ControlToValidate="txtMemberNum" ErrorMessage="[ Membership # ] is required"
CssClass="ValidationMessage" Display="Dynamic" >*</asp:RequiredFieldValidator>
<asp:RegularExpressionValidator ID="revMemberNum" Display="Dynamic" runat="server"
ControlToValidate="txtMemberNum" CssClass="ValidationMessage"
ErrorMessage="[ Membership # ] can only contain letters"
ValidationExpression="^([a-zA-Z\d]+)$" >*</asp:RegularExpressionValidator>
<asp:CustomValidator ID="cvMemberNum" runat="server"
CssClass="ValidationMessage" Display="Dynamic"
ControlToValidate="txtMemberNum" ValidateEmptyText="false"
OnServerValidate="cvMemberNum_Validate"
ErrorMessage="This membership number is already registered">*</asp:CustomValidator>
<asp:ValidationSummary ID="ValidationSummary1" runat="server"
CssClass="ValidationMessage"
ShowMessageBox="True" ShowSummary="False" />
and on the server side:
protected void cvMemberNum_Validate(object source, ServerValidateEventArgs args)
{
try
{
args.IsValid = (!CampaignRegistration.IsMemberRegistered(args.Value));
}
catch
{
args.IsValid = false;
}
}
My problem is: The ValidationSummary never shows the message from CustomValidator. This question has been asked in several places, but I havent seen a satisfactory answer.
Try using a ValidationGroup property across all your validators and the ValidationSummary.
EDIT: Another possibility could be the Server Validation Code
args.IsValid = (!CampaignRegistration.IsMemberRegistered(args.Value));
if CampaignRegistration.IsMemberRegistered(args.Value) is returning false, "!" is making it true and therefore making it valid. I think you should get rid of the "!" as follows:
args.IsValid = CampaignRegistration.IsMemberRegistered(args.Value);
UPDATE: In order for the ValidationSummary to display your custom validator message in a messagebox, you need to have ClientValidationFunction Code. If you need to display just the summary without a popup, this is not needed.
<asp:CustomValidator ID="cvMemberNum" runat="server"
CssClass="ValidationMessage" Display="Dynamic"
ControlToValidate="txtMemberNum" ValidateEmptyText="false"
OnServerValidate="cvMemberNum_Validate"
ClientValidationFunction = "ClientValidate"
ErrorMessage="This membership number is already registered">*</asp:CustomValidator>
//JavaScript Code.
function ClientValidate(source, args)
{
args.IsValid = false; //you need to add validation logic here
}
MORE: If you don't want to do ClientSide Validation, try this trick to show the alert. Make this change to your CustomValidator ServerValidate method:
protected void cvMemberNum_Validate(object source, ServerValidateEventArgs args)
{
bool isValid = true;
try
{
isValid = (!CampaignRegistration.IsMemberRegistered(args.Value));
}
catch
{
isValid = false;
}
args.IsValid = isValid;
if(!isValid)
{
if(!Page.IsClientScriptBlockRegistered("CustomValidation"))
Page.RegisterClientScriptBlock("CustomValidation", "<script>alert('This membership number is already registered');</script>");
}
}
The ShowMessageBox option is fully client-side, so it will only evaluate if you have set the ClientValidationFunction on the CustomValidator.
You can also fake it by registering a script that makes an alert, so when you get back from the server's validation, it'll prompt with the error message. This can either be registered in the ServerValidate method (per #Jose Basilio), or you can call the following method during the PreRender event to register a popup with all invalid validators on the page:
/// <summary>
/// Registers a script to display error messages from server-side validation as the specified <see cref="UserControl"/> or <see cref="Page"/> loads from a postback.
/// </summary>
/// <remarks>
/// Must be called in the PreRender if used to validate against the Text property of DNNTextEditor controls, otherwise Text will not be populated.
/// Must set the ErrorMessage manually if using a resourcekey, otherwise the resourcekey will not have overridden the ErrorMessage property.
/// </remarks>
/// <param name="ctrl">The <see cref="UserControl"/> or <see cref="Page"/> which is being posted back.</param>
/// <param name="validationGroup">The validation group against which to validate.</param>
public static void RegisterServerValidationMessageScript(TemplateControl ctrl, string validationGroup)
{
if (ctrl != null && ctrl.Page.IsPostBack)
{
ctrl.Page.Validate(validationGroup);
if (!ctrl.Page.IsValid)
{
StringBuilder errorMessage = new StringBuilder("<script language='javascript'>alert('");
for (int i = 0; i < ctrl.Page.Validators.Count; i++)
{
IValidator validator = ctrl.Page.Validators[i];
if (!validator.IsValid)
{
errorMessage.Append("- " + validator.ErrorMessage);
if (i < ctrl.Page.Validators.Count - 1)
{
errorMessage.Append(#"\r\n");
}
}
}
errorMessage.Append("');</script>");
ctrl.Page.ClientScript.RegisterStartupScript(typeof(IValidator), "validationAlert", errorMessage.ToString(), false);
}
}
}
I've recently had same problem. ValidationSummary was not showing the ErrorMessage from CustomValidator when ServerValidate stated validation failure. Since by default (as my little reverse engineering showed) validation summary is rendered client side on postback I've simply added a script that checks all validators on document load/async postback completion and triggers validation summary creation for failed validation groups:
$(document).ready(function () {
var displayAlert = function () {
if (typeof Page_Validators == 'undefined') return;
var groups = [];
for (i = 0; i < Page_Validators.length; i++)
if (!Page_Validators[i].isvalid) {
if (!groups[Page_Validators[i].validationGroup]) {
ValidationSummaryOnSubmit(Page_Validators[i].validationGroup);
groups[Page_Validators[i].validationGroup] = true;
}
}
};
displayAlert();
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(
function () {
displayAlert();
});
}
);
In my scenario I had nested user controls with validators, update panel and validation summary at the parent page.
More details here.
You should write a property
ValidationGroup="ValidationSummary1"
at every validator in your case.
Also check if your page has
AutoEventWireup="true"
bduke's RegisterServerValidationMessageScript is "faking it", but it isn't. It really fixes the problem. Every Utility namespace needs this function somewhere.
I have found a workaround for when javascript is disabled and the ValidationSummary does not show the errorMessage property of the CustomValidator. This is required as injecting script or alerts, as described above, will not work.
Add a new Validator control, let's call it CustomValidatorProxy, set its ControlToValidate property to any one of the controls on the form and EnableClientScript=false.
Within the ServerValidate event handler perform your custom validation and if validation fails set the IsValid property of the CustomValidator and CustomValidatorProxy to false and similarly set both ErrorMessage properties.
If the validation in the ServerValidate is passed ensure that the IsValid property of the CustomValidatorProxy is set to true.
Provided the CustomValidatorProxy is before the CustomValidator in the ValidatorCollection of the Page then the ServerValidate handler will override the IsValid property value that the CustomValidatorProxy would have returned having validated the ControlToValidate value and your ErrorMessage from your CustomValidator will be displayed in the ValidationSummary.
This worked for me:
<asp:CustomValidator runat="server" ID="cv"
ClientValidationFunction="ValidateFunction"
ErrorMessage="Default error
message">*</asp:CustomValidator>
<script type="text/javascript">
function ValidateFunction(sender, args)
{
var msg ='';
var formValid = true;
[various checks setting msg and formValid]
if (msg.length > 0) { sender.errormessage = msg; }
args.IsValid = formValid;
}
</script>

Resources