When an Event is triggered by a user in IE, it is set to the window.event object. The only way to see what triggered the event is by accessing the window.event object (as far as I know)
This causes a problem in ASP.NET validators if an event is triggered programmatically, like when triggering an event through jQuery. In this case, the window.event object stores the last user-triggered event.
When the onchange event is fired programmatically for a text box that has an ASP.NET validator attached to it, the validation breaks because it is looking at the element that fired last event, which is not the element the validator is for.
Does anyone know a way around this? It seems like a problem that is solvable, but from looking online, most people just find ways to ignore the problem instead of solving it.
To explain what I'm doing specifically:
I'm using a jQuery time picker plugin on a text box that also has 2 ASP.NET validators associated with it. When the time is changed, I'm using an update panel to post back to the server to do some things dynamically, so I need the onchange event to fire in order to trigger the postback for that text box.
The jQuery time picker operates by creating a hidden unordered list that is made visible when the text box is clicked. When one of the list items is clicked, the "change" event is fired programmatically for the text box through jQuery's change() method.
Because the trigger for the event was a list item, IE sees the list item as the source of the event, not the text box, like it should.
I'm not too concerned with this ASP.NET validator working as soon as the text box is changed, I just need the "change" event to be processed so my postback event is called for the text box. The problem is that the validator throws an exception in IE which stops any event from being triggered.
Firefox (and I assume other browsers) don't have this issue. Only IE due to the different event model. Has anyone encountered this and seen how to fix it?
I've found this problem reported several other places, but they offer no solutions:
jQuery's forum, with the jQuery UI Datepicker and an ASP.NET Validator
ASP.NET forums, bug with ValidatorOnChange() function
I had the same problem. Solved by using this function:
jQuery.fn.extend({
fire: function(evttype){
el = this.get(0);
if (document.createEvent) {
var evt = document.createEvent('HTMLEvents');
evt.initEvent(evttype, false, false);
el.dispatchEvent(evt);
} else if (document.createEventObject) {
el.fireEvent('on' + evttype);
}
return this;
}
});
So my "onSelect" event handler to datepicker looks like:
if ($.browser.msie) {
datepickerOptions = $.extend(datepickerOptions, {
onSelect: function(){
$(this).fire("change").blur();
}
});
}
I solved the issue with a patch:
window.ValidatorHookupEvent = function(control, eventType, body) {
$(control).bind(eventType.slice(2), new Function("event", body));
};
Update: I've submitted the issue to MS (link).
From what you're describing, this problem is likely a result of the unique event bubbling model that IE uses for JS.
My only real answer is to ditch the ASP.NET validators and use a jQuery form validation plugin instead. Then your textbox can just be a regular ASP Webforms control and when the contents change and a postback occures all is good. In addition you keep more client-side concerns seperated from the server code.
I've never had much luck mixing Webform Client controls (like the Form Validation controls) with external JS libraries like jQuery. I've found the better route is just to go with one or the other, but not to mix and match.
Not the answer you're probably looking for.
If you want to go with a jQuery form validation plugin concider this one jQuery Form Validation
Consider setting the hidden field _EVENTTARGET value before initiating the event with javascript. You'll need to set it to the server side id (replace underscore with $ in the client id) for the server to understand it. I do this on button clicks that I simulate so that the server side can determine which OnClick method to fire when the result gets posted back -- Ajax or not, doesn't really matter.
This is an endemic problem with jQuery datepickers and ASP validation controls.
As you are saying, the wrong element cross-triggers an ASP NET javascript validation routine, and then the M$ code throws an error because the triggering element in the routine is undefined.
I solved this one differently from anyone else I have seen - by deciding that M$ should have written their code more robustly, and hence redeclaring some of the M$ validator code to cope with the undefined element. Everything else I have seen is essentially a workaround on the jQuery side, and cuts possible functionality out (eg. using the click event instead of change).
The bit that fails is
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
which throws an error when it tries to get a length for the undefined 'vals'.
I just added
if (vals) {
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
}
and she's good to go. Final code, which redeclares the entire offending function, is below. I put it as a script include at the bottom of my master page or page.
Yes, this does break upwards compatibility if M$ decide to change their validator code in the future. But one would hope they'll fix it and then we can get rid of this patch altogether.
// Fix issue with datepicker and ASPNET validators: redeclare MS validator code with fix
function ValidatorOnChange(event) {
if (!event) {
event = window.event;
}
Page_InvalidControlToBeFocused = null;
var targetedControl;
if ((typeof (event.srcElement) != "undefined") && (event.srcElement != null)) {
targetedControl = event.srcElement;
}
else {
targetedControl = event.target;
}
var vals;
if (typeof (targetedControl.Validators) != "undefined") {
vals = targetedControl.Validators;
}
else {
if (targetedControl.tagName.toLowerCase() == "label") {
targetedControl = document.getElementById(targetedControl.htmlFor);
vals = targetedControl.Validators;
}
}
var i;
if (vals) {
for (i = 0; i < vals.length; i++) {
ValidatorValidate(vals[i], null, event);
}
}
ValidatorUpdateIsValid();
}
This is how I solved a simlar issue.
Wrote an onSelect() handler for the datepicker.
link text
In that function, called __doPostBack('textboxcontrolid','').
This triggered a partial postback for the textbox to the server, which called the validators in turn.
Related
As per requirement I disabled all validation controls in page on PageLoad event in server side.
On clicking submit button I want to activate them and validate the page and if the page is okay submit other wise not.
I am able to enable all validaters but one thing that I am unable to understand is that they do not validate the page. I set alerts and check they are being enabled but they do not validate the page and let the page submit.
I am sorry I couldn't get where I am wrong, may be there need to call some validation method as well or I should prevent default behavior of button. Please guide me.
Below is my script:
<script type="text/javascript">
function NextClicked() {
var _ddlStatus = document.getElementById("<%=ddlEmpStatus.ClientID%>");
var _selectedIndex = _ddlStatus.selectedIndex;
if (_selectedIndex == 0) {
alert("Nothing selected");
}<br/>
else<br/>
if (_selectedIndex == 1) {
for (i = 0; i < Page_Validators.length; i++) {
Page_Validators[i].Enabled = true;
}
}
}
</script>
From the server, you have to have them enabled before the button click; otherwise, I think you need to loop through the server-side collection and enable them, plus call their validate() method explicitly.
Or, you can also try the client-side validatorenable method (http://forums.asp.net/t/1175267.aspx) to enable them.
If you disable by setting Enabled = false from the server, you may have issues even using the client-side API altogether. Not sure about that though, just know that can be an issue with other controls.
HTH.
I have a partial view that is rendered within a main view. The partial view takes advantage of System.ComponentModel.DataAnnotations and Html.EnableClientValidation().
A link is clicked, and div containing the partial view is displayed within a JQuery.Dialog().
I then click the save button without entering any text in my validated input field. This causes the client side validation to fire as expected, and display the '*required' message beside the invalid field.
When the cancel button is clicked, I want to reset the client side MVC validation back to it's default state and remove any messages, ready for when the user opens the dialog again. Is there a recommended way of doing this?
This answer is for MVC3. See comments below for help updating it to MVC 4 and 5
If you just want to clear the validation-messages so that they are not shown to the user you can do it with javascript like so:
function resetValidation() {
//Removes validation from input-fields
$('.input-validation-error').addClass('input-validation-valid');
$('.input-validation-error').removeClass('input-validation-error');
//Removes validation message after input-fields
$('.field-validation-error').addClass('field-validation-valid');
$('.field-validation-error').removeClass('field-validation-error');
//Removes validation summary
$('.validation-summary-errors').addClass('validation-summary-valid');
$('.validation-summary-errors').removeClass('validation-summary-errors');
}
If you need the reset to only work in your popup you can do it like this:
function resetValidation() {
//Removes validation from input-fields
$('#POPUPID .input-validation-error').addClass('input-validation-valid');
$('#POPUPID .input-validation-error').removeClass('input-validation-error');
//Removes validation message after input-fields
$('#POPUPID .field-validation-error').addClass('field-validation-valid');
$('#POPUPID .field-validation-error').removeClass('field-validation-error');
//Removes validation summary
$('#POPUPID .validation-summary-errors').addClass('validation-summary-valid');
$('#POPUPID .validation-summary-errors').removeClass('validation-summary-errors');
}
I hope this is the effect you seek.
If you are using unobtrusive validation that comes with MVC you can simply do:
$.fn.clearErrors = function () {
$(this).each(function() {
$(this).find(".field-validation-error").empty();
$(this).trigger('reset.unobtrusiveValidation');
});
};
------------------------------------------------------------------------
Third Party Edit:
This mostly worked in my case, but I had to remove the $(this).find(".field-validation-error").empty(); line. This appeared to affect the re-showing of the validation messages when resubmitting.
I used the following:
$.fn.clearErrors = function () {
$(this).each(function() {
$(this).trigger('reset.unobtrusiveValidation');
});
};
and then called it like this:
$('#MyFormId input').clearErrors();
function resetValidation() {
$('.field-validation-error').html("");
}
You can simply define a new function in jQuery:
$.fn.resetValidation = function () {
$(this).each(function (i, e) {
$(e).trigger('reset.unobtrusiveValidation');
if ($(e).next().is('span')) {
$(e).next().empty();
}
});
};
and then use it for your input fields:
$('#formId input').resetValidation();
Thank you. I had a similar question for a slightly different scenario. I have a screen where when you click one of the submit buttons it downloads a file. In MVC when you return a file for download, it doesn't switch screens, so any error messages which were already there in the validation summary remain there forever. I certainly don't want the error messages to stay there after the form has been submitted again. But I also don't want to clear the field-level validations which are caught on the client-side when the submit button is clicked. Also, some of my views have more than one form on them.
I added the following code (thanks to you) at the bottom of the Site.Master page so it applies to all of my views.
<!-- This script removes just the summary errors when a submit button is pressed
for any form whose id begins with 'form' -->
<script type="text/javascript">
$('[id^=form]').submit(function resetValidation() {
//Removes validation summary
$('.validation-summary-errors').addClass('validation-summary-valid');
$('.validation-summary-errors').removeClass('validation-summary-errors');
});
</script>
Thanks again.
You can tap into the validation library methods to do this.
There are two objects of interest: FormContext and FieldContext. You can access the FormContext via the form's __MVC_FormValidation property, and one FieldContext per validated property via the FormContext's fields property.
So, to clear the validation errors, you can do something like this to a form:
var fieldContexts = form.__MVC_FormValidation.fields;
for(i = 0; i < fieldContexts.length; i++) {
var fieldContext = fieldContexts[i];
// Clears validation message
fieldContext.clearErrors();
}
// Clears validation summary
form.__MVC_FormValidation.clearErrors();
Then, you can hook that piece of code to whichever event you need.
Sources for this (quite undocumented) insight:
http://bradwilson.typepad.com/presentations/advanced-asp-net-mvc-2.pdf (Mentions FieldContext)
https://stackoverflow.com/a/3868490/525499 (For pointing out this link, which metions how to trigger client-side validation via javascript)
In order to complete clear the validation artifacts including the message, the coloured background of the input field, and the coloured outline around the input field, I needed to use the following code, where this was (in my case) a Bootstrap modal dialog containing an imbedded form.
$(this).each(function () {
$(this).find(".field-validation-error").empty();
$(this).find(".input-validation-error").removeClass("input-validation-error");
$(this).find(".state-error").removeClass("state-error");
$(this).find(".state-success").removeClass("state-success");
$(this).trigger('reset.unobtrusiveValidation');
});
Here you can use simply remove error message
$('.field-validation-valid span').html('')
OR
$('.field-validation-valid span').text('')
I've this issue for "Validation summery" after form ajax submit and done it like this:
$form.find('.validation-summary-errors ul').html('');
and complete code is:
$("#SubmitAjax").on('click', function (evt) {
evt.preventDefault();
var $form = $(this).closest('form');
if ($form.valid()) {
//Do ajax call . . .
//Clear validation summery
$form.find('.validation-summary-errors ul').html('');
}
});
I have a form that has some standard ASP.NET validators and some custom validators.
I know how to force the whole page to validate.
But how on blur of a form field can I force the validator(s) that are looking at the field fire, not all validations on the page.
I expect I am missing some little trick. :(
Well looks like I answered my own question, with some help from George, and the Intertubes.
After seeing this post: I looked at the DOM in Firebug and found the array of Validators. Then it was a matter of getting the right ones, and calling the ValidatorValidate(validator) method.
function callMyValidators() {
// Clean Up Infragistics Ids
var cleanid = this.id.replace(/^igtxt/i,"");
for (var i = 0; i < Page_Validators.length; i++) {
if (Page_Validators[i].controltovalidate === cleanid) {
ValidatorValidate(Page_Validators[i]);
}
}
}
Use the function: ValidatorValidate(val)
http://msdn.microsoft.com/en-us/library/aa479045.aspx
I am trying to disable validators using jquery.
I have already looked
Disable ASP.NET validators with JavaScript
and couple of others doing the same.
It seems ot be working but its breaking.
My code:
$('.c_MyValdiators').each(function() {
var x = $(this).attr('id');
var y = document.getElementById(x);
ValidatorEnable(y[0], false);
});
I get Error:
val is undefined
[Break on this error] val.enabled = (enable != false);\r\n
Alternatively if I use
$('.c_MyValdiators').each(function() {
ValidatorEnable($(this), false); OR ValidatorEnable($(this[0]), false);
});
I get Error:
val.style is undefined
[Break on this error] val.style.visibility = val.isvalid ? "hidden" : "visible";\r\n
Any idea or suggestions?
I beleive that ValidatorEnable takes the ASP.net ID rather that the ClientID produced by ASP.net. You will also need to make the validation conditional in the CodeBehind.
here is an example:
Of particular use is to be able to enable or disable validators. If you have validation that you want active only in certain scenarios, you may need to change the activation on both server and client, or you will find that the user cannot submit the page.
Here is the previous example with a field that should only be validated when a check box is unchecked:
public class Conditional : Page {
public HtmlInputCheckBox chkSameAs;
public RequiredFieldValidator rfvalShipAddress;
public override void Validate() {
bool enableShip = !chkSameAs.Checked;
rfvalShipAddress.Enabled = enableShip;
base.Validate();
}
}
Here is the client-side equivalent:
<input type=checkbox runat=server id=chkSameAs
onclick="OnChangeSameAs();" >Same as Billing<br>
<script language=javascript>
function OnChangeSameAs() {
var enableShip = !event.srcElement.status;
ValidatorEnable(rfvalShipAddress, enableShip);
}
</script>
Reference: http://msdn.microsoft.com/en-us/library/aa479045.aspx
I just stumbled upon your Question [a year later].
I too wanted to disable all validators on a page using JQuery here is how I handled it.
$('span[evaluationfunction]').each(function(){ValidatorEnable(this,false);});
I look for each span on the page that has the evaluatefunction attribute then call ValidatorEnabled for each one of them.
I think the $('this') part of your code is what was causing the hickup.
ValidatorEnable(document.getElementById($(this).attr('id')), true);
I've got another solution, which is to use the 'enabled' property of the span tag for the validator. I had different divs on a form that would show or hide so I needed to disable the validation for the fields inside the hidden div. This solution turns off validation without firing them.
If you have a set of RequiredFieldvalidator controls that all contain a common string that you can use to grab them the jquery is this:
$("[id*='CommonString']").each(function() {
this.enabled = false; // Disable Validation
});
or
$("[id*='CommonString']").each(function() {
this.enabled = true; // Enable Validation
});
Hope this helps.
John
I'm just running into the same problem, thanks to the other answers, as it helped uncover the problem, but they haven't gone into detail why.
I believe it is due to that ValidatorEnable() expects a DOM object (i.e. the validation control object) opposed to an ID.
$(selector).each() sets "this" to the DOM element being currently iterated over i.e. quoted from the jquery documentation:
"More importantly, the callback is fired in the context of the current
DOM element, so the keyword this refers to the element." - http://api.jquery.com/each/
Therefore you do not need to do: document.getElementById($(this).attr('id')
And instead ValidatorEnable(this, true); is fine.
Interestingly, Russ's answer mentioned needing to disable server side validation as well, which does make sense - but I didn't need to do this (which is concerning!).
Scrap my previous comment, it is because I had my control disabled server-side previously.
The ValidatorEnable function takes an object as the 1st parameter and not a string of the id of the object.
Here is the simple way to handle this.
Add a new class to the Validation control.
Then look for that class with jquery and disable the control.
Example :
if (storageOnly == 1)
{
$('#tblAssignment tr.assdetails').addClass('hidden');
$('span[evaluationfunction]').each(function ()
{
if ($(this).hasClass('assdetail'))
{ ValidatorEnable(this, false); }
});
}
else
{
$('#tblAssignment tr.assdetails').removeClass('hidden');
}
* Works like a charm.
** For you imaginative types, assdetail == assignment detail.
Here depending on the if condition, I am either hiding the rows then disabling the validator , or removing hidden class from the rows..
Various ways to this depending on your needs. Some solutions in the following blog posts:
http://imjo.hn/2013/03/28/javascript-disable-hidden-net-validators/
http://codeclimber.net.nz/archive/2008/05/14/How-to-manage-ASP.NET-validation-from-Javascript-with-jQuery.aspx
Is there a client event that I can use for when a DropDownList's data has been loaded/bound onto the control? I need to trigger event on their side when this happens.
Basically, I am trying to lock out the controls while the data is being loaded as if there is a slowdown (not uncommon) a user can start inputting data and then lose focus as they are typing.
I tried doing this in the tags but the methods located there seem to stop working after the first postback! (Any help there would be greatly appreciated). As a workaround I tried attaching the events to the elements themselves and while this works for locking, using the onchange event, I am unable to unlock it upon the data successfully loading!
Any ideas? Thanks for the answers so far :)
Since data will be bound on the server side, you don't have a client-side event for that specific event, however, one the page has rendered, the data will be there, so you may want to run your client script in the document.load event, or using something like jQuery's document.ready event. That will trigger your script to run once the page (including your bound drop down) is finished loading.
Jason is correct here in that you cannot "notify" the client when such an event occurs. One thing you could do, is call the Page.RegisterStartupScript() method to do something with JavaScript once the page has finished loading (and assumedly that the post back that has done your databinding has occurred). Again, this assumes that you want to do something on the client side once the data binding is complete, as opposed to server side.
Are you able to use ASP.NET AJAX in your application? If so, you can have the selected event open up a modal dialog in which you can display your "processing" text while you are populating the drop down list. That way the user does not have access to any other controls and you can do what you need without worry.
i use the following code in my master pages for my websites. This stops the user from attempting to use a control before its completely bound. I have found that if a control hasn't been completely bound (slow connections) then the page blows up.
Essentially the script hijacks the post back if that page isn't done. Allowing the user to not do anything until the page has finished processing. I wrote this a year ago and its come in very handy.
first set the onload body tag to setdopostback()
add this in a scrip block in the body.
var boolDoPostBack = false;
if (__doPostBack)
{
// save a reference to the original __doPostBack
var __oldDoPostBack = __doPostBack;
//replace __doPostBack with another function
__doPostBack = AlwaysFireBeforeFormSubmit;
}
function setdopostback()
{
boolDoPostBack = true;
}
function AlwaysFireBeforeFormSubmit (eventTarget, eventArgument)
{
var x= document.readyState
if (x != "complete")
{
if (x == "loading" || x == "interactive" || x == "unitialized" || x == "loaded")
{
//do nothing with IE postback
}
else if (!boolDoPostBack)
{
//do nothing with FireFox postback
}
else
{
//alert('Allow Postback 1');
return __oldDoPostBack (eventTarget, eventArgument);
}
}
else
{
//alert('Allow Postback 2');
return __oldDoPostBack (eventTarget, eventArgument);
}
}