I have noticed a strange jQuery Validation plugin behaviour, possible a bug (tested with the latest version at http://dev.jquery.com/view/trunk/plugins/validate/jquery.validate.js).
Suppose I have several forms on a page.
This code leads to only first form to be validated:
$(document).ready(function() {
$("form").validate();
});
But this one attaches data validator to all forms:
$(document).ready(function() {
$("form").each(function() {
$(this).validate();
});
});
Is it by design? Why can't I handle all forms at once?
The api for validate does state that it "Validates the selected form" (not forms), but I agree that that's not very jQueryish. Maybe you should suggest it as an enhancement, I can't imagine that breaking any old code?
Related
I'm trying to implement a checkbox captcha I read about here:
http://uxmovement.com/forms/captchas-vs-spambots-why-the-checkbox-captcha-wins/
However I'm having issues adding the checkbox with client side javascript and unobtrusive validation.
I implemented a checkbox with unobtrusive validation based on Darin Dimitrov's answer here: MVC unobtrusive validation on checkbox not working which works perfectly.
However, once I remove the checkbox from my view and add it with this jquery code instead:
jQuery(document).ready(function (jQuery) {
$('div.test').append($("<input>").attr("id", "AcceptsTerms")
.attr("type", "checkbox")
.val("true")
.attr("name", "AcceptsTerms")
.attr("data-val-required", "This field is required.")
.attr("data-val-mustbetrue", "You must accept the terms and conditions")
.attr("data-val", "true")
.addClass("input-validation-error"));
$('div.test').append($('<input>').attr("type", "hidden")
.val("value", "false")
.attr("name", "AcceptsTerms"));
$('div.test').append($("<label>").attr("for", "AcceptsTerms")
.html("Accept terms and conditions"));
$('div.test').append($('<span>').addClass("field-validation-error")
.attr("data-valmsg-replace", "true")
.attr("data-valmsg-for", "AcceptsTerms"));
});
it no longer wants to validate. Are there any known issues with adding form elements after the document has loaded and unobtrusive validation? If so, has any attempted to implement this or have any suggestions on how to go about this?
Looks like I found the solution.
As I suspected and as Sparky mentioned: the jQuery Validate plugin is initialized once on the DOM ready event. Due to this, all I had to do after adding my input dynamically was to reinitialize unobtrusive validation.
I added this first for the rule:
$.validator.unobtrusive.adapters.addBool("mustbetrue", "required");
Then I added this to reinitialize unobtrusive validation:
$("form").removeData('validator');
$("form").removeData('unobtrusiveValidation');
$.validator.unobtrusive.parse($("form"));
Quote OP:
However, once I remove the checkbox from my view and add it with this
jquery code instead: {snip} it no longer wants to validate. Are there
any known issues with adding form elements after the document has
loaded and unobtrusive validation? If so, has any attempted to
implement this or have any suggestions on how to go about this?
This happens because the jQuery Validate plugin is initialized once on the DOM ready event but your checkbox does not yet exist. It's an all-too-common misconception that .validate() is called repeatedly as the user interacts with the form. It is not. .validate() is called once on DOM ready to initialize the plugin and form validation happens automatically when triggered by the default events.
If you need to dynamically alter the form's HTML, you must use one of the plugin's built-in methods to dynamically alter its options.
In your case, you need to use the rules('add') method, sometime after your jQuery adds the checkbox, to alter the rules option to apply your checkbox rule(s).
$(document).ready(function() {
$('div.test').append($("<input>").attr("id", "AcceptsTerms"). ... );
$('#AcceptsTerms').rules('add', {
required: true,
another_rule: parameter,
messages: { // <- this item is optional
required: "custom message"
another_rule: "custom message for this rule"
}
});
...
});
In the new version of jQuery validation plugin 1.9 by default validation of hidden fields ignored. I'm using CKEditor for textarea input field and it hides the field and replace it with iframe. The field is there, but validation disabled for hidden fields. With validation plugin version 1.8.1 everything works as expected.
So my question is how to enable validation for hidden fields with v1.9 validation plugin.
This setting doesn't work:
$.validator.setDefaults({ ignore: '' });
The plugin's author says you should use "square brackets without the quotes", []
http://bassistance.de/2011/10/07/release-validation-plugin-1-9-0/
Release: Validation Plugin 1.9.0:
"...Another change should make the setup of forms with hidden elements
easier, these are now ignored by default (option “ignore” has
“:hidden” now as default). In theory, this could break an existing
setup. In the unlikely case that it actually does, you can fix it by
setting the ignore-option to “[]” (square brackets without the
quotes)."
To change this setting for all forms:
$.validator.setDefaults({
ignore: [],
// any other default options and/or rules
});
(It is not required that .setDefaults() be within the document.ready function)
OR for one specific form:
$(document).ready(function() {
$('#myform').validate({
ignore: [],
// any other options and/or rules
});
});
EDIT:
See this answer for how to enable validation on some hidden fields but still ignore others.
EDIT 2:
Before leaving comments that "this does not work", keep in mind that the OP is simply asking about the jQuery Validate plugin and his question has nothing to do with how ASP.NET, MVC, or any other Microsoft framework can alter this plugin's normal expected behavior. If you're using a Microsoft framework, the default functioning of the jQuery Validate plugin is over-written by Microsoft's unobtrusive-validation plugin.
If you're struggling with the unobtrusive-validation plugin, then please refer to this answer instead: https://stackoverflow.com/a/11053251/594235
This worked for me, within an ASP.NET MVC3 site where I'd left the framework to setup unobtrusive validation etc., in case it's useful to anyone:
$("form").data("validator").settings.ignore = "";
Make sure to put
$.validator.setDefaults({ ignore: '' });
NOT inside $(document).ready
So I'm going to go a bit deeper in to why this doesn't work because I'm the kind of person that can't sleep at night without knowing haha. I'm using jQuery validate 1.10 and Microsoft jQuery Unobtrusive Validation 2.0.20710.0 which was published on 1/29/2013.
I started by searching for the setDefaults method in jQuery Validate and found it on line 261 of the unminified file. All this function really does is merge your json settings in to the existing $.validator.defaults which are initialized with the ignore property being set to ":hidden" along with the other defaults defined in jQuery Validate. So at this point we've overridden ignore. Now let's see where this defaults property is being referenced at.
When I traced through the code to see where $.validator.defaults is being referenced. I noticed that is was only being used by the constructor for a form validator, line 170 in jQuery validate unminified file.
// constructor for validator
$.validator = function( options, form ) {
this.settings = $.extend( true, {}, $.validator.defaults, options );
this.currentForm = form;
this.init();
};
At this point a validator will merge any default settings that were set and attach it to the form validator. When you look at the code that is doing the validating, highlighting, unhighlighting, etc they all use the validator.settings object to pull the ignore property. So we need to make sure if we are to set the ignore with the setDefaults method then it has to occur before the $("form").validate() is called.
If you're using Asp.net MVC and the unobtrusive plugin, then you'll realize after looking at the javascript that validate is called in document.ready. I've also called my setDefaults in the document.ready block which is going to execute after the scripts, jquery validate and unobtrusive because I've defined those scripts in the html before the one that has the call in it. So my call obviously had no impact on the default functionality of skipping hidden elements during validation. There is a couple of options here.
Option 1 - You could as Juan Mellado pointed out have the call outside of the document.ready which would execute as soon as the script has been loaded. I'm not sure about the timing of this since browsers are now capable of doing parallel script loading. If I'm just being over cautious then please correct me. Also, there's probably ways around this but for my needs I did not go down this path.
Option 2a - The safe bet in my eyes is to just replace the $.validator.setDefaults({ ignore: '' }); inside of the document.ready event with $("form").data("validator").settings.ignore = "";. This will modify the ignore property that is actually used by jQuery validate when doing each validation on your elements for the given form.
Options 2b - After looking in to the code a bit more you could also use $("form").validate().settings.ignore = ""; as a way of setting the ignore property. The reason is that when looking at the validate function it checks to see if a validator object has already been stored for the form element via the $.data() function. If it finds a validator object stored with the form element then it just returns the validator object instead of creating another one.
This worked for me within an ASP.NET site.
To enable validation on some hidden fields use this code
$("form").data("validator").settings.ignore = ":hidden:not(#myitem)";
To enable validation for all elements of form use this one
$("form").data("validator").settings.ignore = "";
Note that use them within $(document).ready(function() { })
Just added ignore: [] in the specific page for the specific form, this solution worked for me.
$("#form_name").validate({
ignore: [],
onkeyup: false,
rules: {
},
highlight:false,
});
This is working for me.
jQuery("#form_name").validate().settings.ignore = "";
The validation was working for me on form submission, but it wasn't doing the reactive event driven validation on input to the chosen select lists.
To fix this I added the following to manually trigger the jquery validation event that gets added by the library:
$(".chosen-select").each(function() {
$(this).chosen().on("change", function() {
$(this).parents(".form-group").find("select.form-control").trigger("focusout.validate");
});
});
jquery.validate will now add the .valid class to the underlying select list.
Caveat: This does require a consistent html pattern for your form inputs. In my case, each input filed is wrapped in a div.form-group, and each input has .form-control.
Just find the text ignore: ":hidden" in your jquery validation file and comment it.
After comment this it will never loss any hidden elements to validate...
Thanks
I have created 2 examples, one with Jquery Validate 1.9 and other with Jquery Validate 1.6. I have one form in which I have created tabs with the help of Jquery UI. I want that when user click a button all tabs should be validated. Jquery Validate 1.6 does this but Jquery validate 1.9 only validate current selected/visible tab. To highlight error tabs I am using some code I found on net. This code is working with 1.6 but not working with 1.9.
Please refer following links for example.
http://micmindia.com/JqueryValidate1.6/JqueryUIValidate1.6WithTabs.html
http://micmindia.com/JqueryValidate1.9/JqueryUIValidate1.9WithTabs.html
Answer:
Author of the library has helped in solving the problem
$("#validatetabs").validate({
ignore: [], //This has to be addedd
highlight: function (input) {
$(input).addClass("ui-state-error");
},
submitHandler: function (form) {
//return true;
},
invalidHandler:.....
the above change has been described in this change log
://github.com/jzaefferer/jquery-validation/commit/21707129666012f6b0bc60622eb3bcb9f87daa04
I have a form and unobtrusive validations are enabled. By default in submit method client side validation gets triggered and (if you have any errors) the form looks like this:
The validation happens even before any data gets sent to the server.
Now this behavior doesn't work if you want to use $.ajax method. Client side validation doesn't work. You have to manually check all the fields in your javascript, losing all the beauty of DataAnnotations.
Is there any better solution? I could've use jquery's submit() but I guess it doesn't have callback like $.ajax.
Oh...
if (form.valid()) // do submit
You must force the form to validate before checking if it is valid. Something like this:
var form = $( "#myform" );
form.validate();
if (form.valid()) {
// ...
}
I did...
$("#form-submit-button").click(function (e) {
e.preventDefault(); // Stops the form automatically submitting
if ($("#my-form").valid()) {
$("#my-form").submit();
}
});
This also seems to be a good solution if you have say textboxes with a plugin to make those textboxes into a calendar control. Only reason I say this is because I used Zebra Datepicker with an MVC form and it would submit an invalid form if focus was on the calendar date picker. Using the below code stops this.
I was having the same issue Yablargo was having in that it was saying that valid is not a function, so I came up with this:
For the onclick handler of the submit button, I put this:
onclick="return $(this).closest('form').checkValidity();"
I'm in the process of converting my web app to a fully AJAX architecture.
I have my master page that is initially loaded and a div container that is loaded with dynamic content.
I created a few jQuery plugins that I apply to certain elements in order to extend their functionality. I'd normally call the functions as follows during each page load:
$(document).ready(function () {
// Enable fancy AJAX search
$(".entity-search-table").EntitySearch();
});
This would find the appropriate div(s) and call the plugin to enable the necessary functionality.
In an AJAX environment I can't just apply the plugin during the page load since elements will be added and removed dynamically.
I'd like to do something like this:
$(document).ready(function () {
// Enable fancy AJAX search
$(".entity-search-table").live("load", function () {
$(this).EntitySearch();
});
});
Question: Is there any way that I can trigger an event when a <div> or other element that matches a selector is added to the DOM?
It seems incredibly wasteful to activate the plug-in every time an AJAX request completes. The plug-in only needs to be applied to the element once when it is first added to the DOM.
Thanks for any help!
Yes - take a look at liveQuery. Example:
$('.entity-search-table').livequery(function(){
$(this).EntitySearch();
});
It seems incredibly wasteful to activate the plug-in every time an AJAX request completes. The plug-in only needs to be applied to the element once when it is first added to the DOM.
You can get the best of both worlds here, for example:
$("#something").load("url", function() {
$(".entity-search-table", this).EntitySearch();
});
This way it's only applying the plugin to the .entity-search-table elements you just loaded, since we specified a context to $(selector, context) to limit it.
The DOM 2 MutationEvent is what you really want, but unfortunately it isn't supported by IE. You'll need to either use live()/ delegate() binding in the plug-in, or (as I did when I had to work around this) use callbacks from your AJAX loaders indicating the scope of what has changed.
Use the live binding in your plugin code directly
jQuery.fn.EntitySearch = function() {
this.live(..., function(){ your plugin code });
return this;
}