Why does CustomValidator fire on textbox's onblur - asp.net

I am building a CustomValidator to handle my own application's logic on time fields ("09:00", "15:35", ...) but I am stumbling on a behaviour that I haven't found any explanation for online.
My focus right now is the validation logic that gets executed client-side.
The problem is, as said in the title, that, if and only if I set the ControlToValidate property in the Validator with the ID of the textbox I am validating, the validation gets fired as soon as focus leaves the textbox; it even fires before the onblur event, which is absolutely detrimental for me, since I am using the onblur event to standardize the time formats (eg "9:00" -> "09:00", "11.45" -> "11:45") and thus, the validation logic potentially receives an incorrect value. If, on the other hand, the ControlToValidate property remains blank, the ClientValidationFunction is fired only on a submit/postback.
The only related answer I've found is this https://stackoverflow.com/a/8649697/450684, but still, to me it makes no sense at all. Why should the presence of a ControlToValidate indicate that I want client-side validation to execute before onblur? I don't want it! Is there any way to supress this behaviour?
Here is an example page:
<asp:TextBox runat="server" AutoPostBack="false" ID="txtBox1" onblur="FormatText(this);" />
<asp:CustomValidator runat="server" ID="CV1" ControlToValidate="txtBox1" ClientValidationFunction="Test1" />
<asp:CustomValidator runat="server" ID="CV2" ClientValidationFunction="Test2" />
<asp:Button ID="btn1" Text="postback" runat="server" OnClick="btn1_Click" />
<asp:Label ID="lbl1" runat="server" />
<script type="text/javascript">
function FormatText(txtBox1)
{
alert('FormatText');
}
function Test1(val, args)
{
alert('Test1');
}
function Test2(val, args)
{
alert('Test2');
}</script>
What I want is both Test1 and Test2 to execute only on btn1's click; instead on txtBox1's onblur event I get Test1 and FormatText executing in this order
ASP.NET's client validation was really fun for me to write and study, don't let this ruin everything :-)
Thx
PS: .NET framework's version is 4.0. Plus, the server-side language is C#, if it matters

I think what is going on is this:
The standard behavior for ASP.NET client-side validation is to validate when the field is exited. That's an observation, not a reference to a published standard (although there may be one.) The out-of-the-box validators all behave this way. All of them require specifying a particular field to validate.
The custom validator allows you to validate a single control (by specifying it with ControlToValidate), or lets you validate a combination of controls, in which case you set ControlToValidate to an empty string. Unless things have changed, you do have to specify it; if you omit the attribute, no validation will occur.
So ... if you specify a control to validate, the custom validator behaves like every other validator and reacts to the user exiting the field. If you don't specify a control to validate, it doesn't know what controls you're interested in, and doesn't do that.
You may be able to work around this by writing a truly custom validator: inherit from BaseValidator. That can actually be a lot of fun.

How to manage events of validation for your control.
You can remove ControlToValidate property from your validator and bind validation for your textbox on textbox event as you wish. You can add some function logic before or after validation also. On button click event validation stay the same without change.
function BindValidation(){$('#txtBox1').on('blur keyup change',function(){ValidatorValidate($('#CV1').get(0));});}
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(BindValidation);
//validation function example for CV1 validator
function Test1(val, args)
{
args.IsValid=$('#txtBox1').val().length>0&&$('#txtBox1').val().match(/^\s+$/g)==null;
}

Related

Why does a failed validation prevent postbacks from control in other validation groups?

I have an asp.net web form with several textboxes, buttons, and other controls. One of the buttons is supposed to trigger validation of content in some of the textboxes. This works fine, except that if validation fails, all subsequent postbacks of the page are prevented. Fixing the invalid values gets rid of the error messages, but postback still does not occur.
The validation is occurring within an AJAX UpdatePanel. I'm not sure if that matters or not.
I'm glad the workaround is fine for you, but for the benefit of others who land this page, disabling client side validation is far from an acceptable solution. So here goes:
Why it happened only when UpdatePanel was around, is still unclear to me, however:
As others have mentioned, the issue you were having is most likely because the unsuccessful validation attempt is preventing a further postback.
See also: Why won't my form post back after validation?
There is a variable called Page_BlockSubmit which is set to true when client side validation fails:
function Page_ClientValidate(validationGroup) {
....
Page_BlockSubmit = !Page_IsValid;
return Page_IsValid;
}
So when a __doPostBack occurs as part of, say, an OnSelectedIndexChanged of a DropDownList, there is this check:
function ValidatorCommonOnSubmit() {
....
var result = !Page_BlockSubmit; /* read the value */
....
Page_BlockSubmit = false; /* reset it */
return result;
}
Which will block the first time, but then clear the flag, so the next postback attempt should work.
The workaround, in my case, for a DropDownList's OnSelectedIndexChanged event, was to have a snippet added to its client-side onchange event:
<asp:DropDownList runat="server" ID="SomeDropDownList" OnSelectedIndexChanged="AlwaysDoSomething"
onchange="resetValidationState(this);">
....
</asp:DropDownList>
<script type="text/javascript">
function resetValidationState() {
// clear any postback blocks, which occur after validation fails:
window.Page_BlockSubmit = false;
}
</script>
You might get away with putting that snippet into the onchange itself.
except that after this button has been clicked no other button can cause a postback unless the validation errors have been corrected. So, btnDelete, which should not require validation of the textboxes, cannot postback until the textbox values are corrected
Don't see that behavior with following code..
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="RequiredFieldValidator" ControlToValidate="TextBox1" ValidationGroup="pc">
</asp:RequiredFieldValidator>
<asp:Button runat="server" ID="btnSubmit" Text="Submit" Width="150" CausesValidation="true" ValidationGroup="pc" />
<asp:Button runat="server" ID="btnDelete" Text="Delete" CausesValidation="false" />
I could be totally off base here - but i think I see the problem. (I work mainly with devexpress controls so the rules can be a bit different). When validation fails, the whole page is set to invalid, so no postbacks can occur. Can it be since the delete button is not causing any validation, its not re validating after those editors have been changed to be valid?

LinkButton not firing ASP.NET validators

I have a form that currently uses an control to submit a form. Everything works perfectly. So now the new requirement is for the "submit' button to be a link. Changing it to a LinkButton control, without changing a SINGLE other thing, breaks the validation.
There is a bit too much code to post in a SO question and I know there's a bit of a lack of detail here, but is there any reason why a LinkButton wouldn't fire ASP.NET validation the same way a Button control would? In theory, they should both operate exactly the same, no?
The current submit button:
<asp:Button ID="btnSubmit" TabIndex="9" Text="Send" ValidationGroup="Forward" runat="server" />
The new submit button:
<asp:LinkButton ID="btnSubmit" TabIndex="9" Text="Send" ValidationGroup="Forward" runat="server" />
The Link button should fires the validation the same way a normal button does, my concerns in your case would be the following:
make sure these is nothing in the server side code stopping this.
make sure in the javascript code there is nothing stopping the "
ASP.NET controls that fire validation has a property called CauseValidation
Be sure all controls should fire validation, has this property set to True
Add attribute CauseValidation="True" to your control but if you want to fire this at particular line at code behind you can use validate the form by the following code:
FormID.Validate();
I know this is old but it has never answered. Did your validator have a "controlTovalidate"? Currently it would appear as if the validator was not firing but in reality it is. It just does not have anything that it is 'watching'. Hope if anyone reaches this thread that this helps even if it is just a little bit.
I was unable to determine the cause of this issue but was able to solve it:
I set the CausesValidation="false" and added at the top of the onclick event this.Validate(linkButton.ValidationGroup) this allows the event to get to the code behind and validation to occur.

how to check a particular asp.net validation control is valid?

In a web form there are different asp.net validation controls. Is it possible to check a particular validation control is valid ? For example on leaving focus of textbox, first I will check requiredFieldValidatorUserName is valid ? If it is valid then I will check on server using ajax that this user name is not booked already.
Edit:
Explaination: I want to check validity (that input was valid) of a validation control on client side.
Please guide.
All validator controls implement IValidator which contains the IsValid property.
myValidatorControl.IsValid
The best way would be to use a CustomValidator with client side code, as this will display all the error messages, block form submission and also ensure that the validation is repeated at the server side - remember, just because you have client-side validation available, doesn't mean the user's seen it: Always validate your input at the server as well.
Your CustomValidator would then be coded to call the Ajax methods, and would show the error messages correctly to the client:
<asp:Label ID="UserNameLabel" AssociatedControlID="UserName" runat="server">
UserName *:</asp:Label>
<asp:TextBox ID="UserName" runat="server" />
<asp:RequiredFieldValidator ID="UserNameRequired" runat="server"
ControlToValidate="UserName" EnableClientScript="true"
ErrorMessage="You must supply a username!" />
<asp:CustomValidator ID="UserNameCustom" runat="server"
ControlToValidate="UserName"
ClientValidationFunction="CheckExisting"
OnServerValidate="UserNameCustomValidate"
ErrorMessage="Username already taken" />
And your ClientValidationFunction should look something like:
<script type="text/javascript">
function CheckExisting(source, arguments) {
// Pass the arguments.Value to your AJAX call:
if (ajaxCallUserNameTaken(arguments.Value)) {
arguments.IsValid = false;
}
}
</script>
(Obviously, you'll need to write the ajaxCallUserNameTaken method to call your page method/web service/etc.)
Doing it this way will ensure that the validation methods happen as expected; this will get called whenever the user tabs out of the textbox leaving a value (it won't get called if the textbox is empty), and will ensure that the user can't submit the page until they supply a unique value. You'll also want to create the method referenced in OnServerValidate to ensure that the value's good once it hits the server too - this should call the same code that the AJAX endpoint uses to reduce duplication of code, etc.
I was originally going to suggest that you could use the Page_Validators object on the client-side to do some checking in the onBlur event, but I don't really think this is suitable here as it results in more pain:
It assumes that although there might be more than one validator on the page, there's only the RequiredFieldValidator on the control we're checking
The RequiredFieldValidator isn't fired during OnBlur if a user moves out of a control without setting a value - only if they set and clear the value, so even if isvalid is true, you need to check for an empty string!
You could do this by setting the ValidationGroup for the Validator control that you want to treat as separate from the others. Make sure it matches the ValidationGroup of the control it's validating (your username field).
I have just faced the same issue and I Set CausesValidation="true" to the textbox control and it worked. Just give it a try :)
I have been messing around with this around for a bit and found a rather easy (not so efficient) solution to handle this using jQuery.
Use this function to check the validity of your control:
function validateControl() {
return $('#YOUR_VALIDATOR_ID').css("visibility") == "visible"
if you're using Display="Dynamic" on your validator then the function is like so:
function validateControl() {
return return $('#YOUR_VALIDATOR_ID').css("display") == "inline"
Be sure to check the true ID of your validator if you're using a Masterpage, as it will be different than the one in your IDE. Do so by viewing the page source in your browser.
The best solution will be of course to validate your form in some other way, using JavaScript or a CustomValidator that lets you write your own code.

How do you reenable a validation control w/o it simultaneously performing an immediate validation?

When I called this function to enable a validator from client javascript:
`ValidatorEnable(document.getElementById('<%=valPassportOtherText.ClientID%>'), true); //enable` validation control
the required validation control immediately performed it validation, found the value in the associated text box blank and set focus to the textbox (because SetFocusOnError was set to true). As a result, the side effect was that focus was shifted to the control that was associated with the Validation control, i teh example, txtSpecifyOccupation.
<asp:TextBox ID="txtSpecifyOccupation" runat="server" AutoCompleteType="Disabled"
CssClass="DefaultTextBox DefaultWidth" MaxLength="24" Rows="2"></asp:TextBox>
<asp:RequiredFieldValidator ID="valSpecifyOccupation" runat="server" ControlToValidate="txtSpecifyOccupation"
ErrorMessage="1.14b Please specify your <b>Occupation</b>"
SetFocusOnError="True"> Required</asp:RequiredFieldValidator>
Perhaps there is a way to enable the (required) validator without having it simultaneously perform the validation (at least until the user has tabbed off of it?)
I'd like validation of the txtSpecifyOccupation textbox to occur only on a Page submit or when the user has tabbed of the required txtSpecifyoccupation textbox.
How can I achieve this?
Don't call the ValidatorEnable method. Instead, get a reference to teh validation control and simply set its "enabled" property as desired.
To clear the validation control's error text, set the innerText property to "".

Client-Side validation with groups

I have several tabs that are loaded via ajax, and each one has a set of validators. I want to allow the user to change tabs only if the tab is valid
I thought setting a validationgroup to the validators and then check for the specific group like this, would work:
function validatePage(group) {
return Page_ClientValidate(group);
}
However, when I call the function, it always returns true. Can anyone see what I'm doing wrong?
I check it like this
alert(validatePage("presentaciones"));
And I have some validators:
// (...)
<asp:TextBox ValidationGroup="presentaciones" id="txtDescription" runat="server" Text='<%# Eval("Description") %>' MaxLength="50" />
<asp:RequiredFieldValidator ID="DescriptionRequiredFieldValidator" runat="server" ControlToValidate="txtDescription" SetFocusOnError="true" ValidationGroup="presentaciones" ErrorMessage="Debe ingresar una descripciĆ³n" Display="Dynamic" />
// (...)
I have made groups work server-side with Page.Validate(group) but I wasn't aware this could be done client-side. Perhaps you need to implement a custom validation control that checks the status of each tab.
My guess is that the validation scripts are not being wired up. In your function do an alert((typeof(Page_Validators) == "undefined")) and see if it displays true. You said you are loading the tabs via ajax. You may want to see if placing a validator on the page somewhere will help wire up the validation scripts.
The other thing to watch for is Firefox and legacy rendering mode....client side just plain does not work in that scenario.
This can be done on the client side. Like this:
$('.buttonWithSameValidationGroup').bind('click', function () {
if (Page_ClientValidate($(this).attr('validationgroup'))) {
//do stuff
}
});
Sometimes you might need to add the following server side code in the Page Pre_Render method
button1.AddAttributes("validationgriup","group1");

Resources