jQuery Validator: Validate form that is not attached to DOM - javascript

I'm having trouble when I try to validate a form with the jQuery Validator plugin. So in this case, I have constructed a div table (not table elements, but divs styled as a table) where each row essentially is its own form complete w/ whatever form-controls.
Since this table could have potentially hundreds of rows however, I didn't want the overhead of wrapping each row element in its own separate form. So I came up with an idea where the save method just takes the row itself as an arg in order to create/validate/submit a form behind the scenes.
What I do is essentially clone the row and append the clone onto a new form I create like so
$("<form></form>").append(clonedRow);
Then I take the resulting variable (the form) and setup the validation. The validation options/setup look like this:
form.validate({
rules: {
Follow_Up_Code: { required: true, maxlength: 2 }
},
messages: {
Follow_Up_Code: { required: "...", maxlength: "..." }
},
submitHandler: function(){...}
});
Currently I only want to validate against one input in this row to test. Here is the input markup:
<input type="text" class="get set input" name="Follow_Up_Code" style="width: 100%;">
After the form runs .validate(), I immediately submit the form. However, for my test case the form passes validation and runs the SubmitHandler set up in the validator every time.
This leads me to think that any form I want to validate with this plugin needs to be attached to the DOM in order to validate properly. However I've found no documentation on this. I would like to know if there is a way I could fix this, or if I'm better off trying to find/create my own validation service for this purpose.

After testing, I've come to discover that. Yes, the form needs to be attached to the DOM in some way shape or form. However, you can get around this pretty easily and unobtrusively:
form.css({ position: "absolute", visibility: "hidden", left: "-5000px" });
$("body").append(frm);
frm.submit();
That way the user won't be able to see or interact with this form while it's on the DOM.
This will get the job done and validate the form. In this case however, if there were any validation errors that I would want to show on the original table. I would have to access the invalid controls from inside the validator's invalidHandler option on setup. From there I just need to insert the error message(s) at where my desired location happens to be.
After all is said and done, it would be a good idea to .destroy the validator and remove that form from the DOM. I believe doing this at the end of both the submit handler and invalid handler would be the best way to go about that.

Related

jquery validation plugin detects errors, but no messages appear, why not?

I'm using the jQuery Validator plugin 1.19.5 on a slightly large (but simple) form generated from a PDF by an online converter to html5
The form has a Submit button implemented as a button with onclick to a javascript function within the formviewer.js file that is part of the conversion to html5. If I open the form in Chrome 107.0.5304.107 Developer Tools, I can see that the Submit button goes to the following code that I added to the success branch of the function that handles the submit in formviewer.js:
success: function() {
const OSHform=$("form").eq(0);
if (OSHform.valid()) {
top.document.location.href = "/Adsentry/completed";
}
else {
alert("Fields did not validate, please fix errors and try again");
}
},
failure: function() {
alert("Form failed to submit, please try again")
}
In a separate script, I invoked validate() on the form element, passing it rules for the fields to validate.
var $j = jQuery;
var OSHform = $j("form");
OSHform.validate({
rules: {
"NAME OF DRIVER": "required",
"EMAIL": "required",
"EMAIL": "email",
"ADDRESS": "required"
}
});
If I omit required fields, or enter an invalid email address in an email field, the call to valid() returns false. And in fact, if I look at the input elements in the Elements tab, I can see that class="error" gets added, and if I correct the error it changes to class="valid". Additionally, with class="error", a label gets added for that element, also with class="error", and correcting the problem adds style="display:none;" to the label.
So everything is great, except that there is no text or message that goes with the label, so its presence/absence, or the presence/absence of display:none on it, has no effect on the normal display of the page.
I have tried stepping through the code in the debugger, but I'm afraid my javascript is so weak I can't really figure out what's going on to the extent of understanding why the messages are not being displayed.
You can play with it live here for the time being, but I can't promise to stop fiddling with it! There are currently only 3 required fields: Name of driver, Address, and Email. If they are all correct, the form submits as intended.
A little disappointed that this didn't even get any comments, let alone answers. On the other hand, it turned out the answer was exactly as anyone even slightly more experienced than me would likely have guessed: errors were being reported in HTML elements, but there was no CSS to put them in the right location on the page. The plugin seemed to be buggy in failing to produce default message text describing the errors; instead, it just produced message text that was simply the name attribute of the erroneous input element. But without appropriate CSS, that name attribute was output in the black strip at the bottom of the page, making it essentially invisible. It took a sharp eye to notice the sudden appearance of "fly specs" at the bottom of the page when clicking the submit button.
The plugin just inserts an HTML element into the DOM immediately following the bad input element. But the files generated from the PDF include a style sheet with selectors using the ID of each input element to give the input element absolute placement on the page. And simply inserting an element into the DOM as the next sibling of the input element, without a style, results in having it rendered at the bottom of the page. Even when I figured out that the lack of CSS was the problem, it took me a while to get something that worked: good old selector specificity in action. All of the input elements were placed using ID selectors with absolute position, and I could find no way to have the simple next-sibling relationship of the message to the input element cause the message to be rendered immediately after the input element. Although it made me feel "icky" to do it, the solution I came up with was to use jQuery to iterate over all the message elements with the "error" class, get the ID of the input element it was reporting, and then use $.css() to get the input element's effective top, left, and width style attributes. Then strip off the trailing "px", multiply by 1 to get a numeric value, add the width to the left numeric value, and specify new top and left attributes using $.css() on the message elements. This put the messages I defined in the messages sub-object of the object passed to the validate constructor appear in the right locations. It only remains a mystery why the default messages didn't appear instead of the names of the input elements for elements that were invalid.

Make jQuery validator validate hidden inputs on submit [duplicate]

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

MVC 5 - Validate a specific field on client-side

I want to populate a city/state drop down list based on the postal code a user types into a textbox. So when the text changes, I'm going to make an ajax call to retrieve the data. However, I only want to perform that ajax request for valid postal codes. The field already validates using the DataAnnotations.RegularExpression attribute and jquery.validate.unobtrusive validation library. I'm unclear on what can and can't be used from jquery.validate when using unobtrusive. I've looked at the unobtrusive code, but haven't gotten an understanding of it yet. So two questions:
Using javascript,
is there a way to force validation on a specific field, not the whole form?
is there a way to check whether a specific field is valid?
After digging around in the source code, I've come to these conclusions. First, the purpose of unobtrusive is to wire up the rules and messages, defined as data- attributes on the form elements by MVC, to jQuery.validation. It's for configuring/wiring up validation, not a complete wrapper around it, so when it comes to performing validation that is already set up, you don't have to worry about "circumventing", or not involving, unobtrusive.
So to answer the questions:
Yes, there are two ways. The Validator.element(element) function and the $.fn.valid() extension method. .valid actually calls Validator.element internally. The difference is .valid works on a jQuery which allows you to perform the validation on one or more fields (or the form itself). Validator.element performs validation on only a single element and requires you to have an instance of the validator object. Although the documentation states .validate() "validates the selected form", it actually appears to initialize validation for the form, and if it has already been called, it simply returns the validator for the form. So here are examples of two ways to validate an input (below #2).
Yes, but not without also performing the validation. Both of the methods from #1 return a boolean so you can use them to determine whether a field is valid. Unfortunately there doesn't appear to be anything exposed by the library that allows you to check the validation without, in effect, showing or hiding the validation message. You would have to get at and run the rule(s) for the field from your code, which may be possible, but my need didn't justify spending the time on it.
Example:
<form>
<input id="txtDemo" type="text"></input>
</form>
...
<script type="text/javascript">
$("#txtDemo").valid();
//or
//Get the form however it makes sense (probably not like this)
var validator = $("form").validate();
//Note: while .element can accept a selector,
//it will only work on the first item matching the selector.
validator.element("#txtDemo");
</script>
you can find if a single field is valid and trigger this validation this way:
$("#myform").validate().element("#elem1");
details here http://docs.jquery.com/Plugins/Validation/Validator/element#element
Use like this:
$('#Create').on('click', function () {
var form = $('#test').closest('form');
$(form).validate();
if (!$(form).valid()) {
return
} else {
// Bide the data
}
});
Hope it works for you

How to implement my idea of a JavaScript form?

I have worked mostly with Python so far, so I'm a newbie when it comes to JavaScript. Now I need the latter to implement a form. I have some ideas and requirements in mind and would like you to tell me how to start and which frameworks or tools to use.
My requirements are:
The server-side logic will be implemented in Python and Django.
The entire form is located on a single webpage.
The overall design of the webpage should be done with Twitter Bootstrap.
When the page has been loaded, only the first field of the form is displayed.
When this field has been filled and validates correctly, display the second field of the form below the first field
When a new field gets displayed, its webpage should scroll down automatically if necessary, so that the new field gets centered in the browser. The scrolling should occur with some nice animation.
My form also includes some fields of type ChoiceField. Each choice has its own set of additional settings which will be implemented as form fields as well. Once a particular choice has been made, only the respective set of settings should be displayed but not all settings for all choice fields at the same time. (Can I probably do this with a simple if-else structure?)
When all fields have been displayed, filled and validated and the form has been submitted, the server does some computations. The results of these computations should be displayed below the entire form, once they are ready. The webpage should again scroll down automatically to the results. The best would be to scroll down the webpage to an extent where the form is not visible anymore but only the results. So this is probably dependent on the size of the currently opened browser window.
I know that all of this is possible and I've also seen forms like that from time to time but don't have a concrete example at the moment. I also know that all of this is possible with JavaScript. Can I implement all of the above with JQuery or do I need additional tools? It would be great if a JavaScript expert guided me a bit through this mess inside my mind. Thank you in advance!
Make it work
Before doing anything with javascript make a normal form that works. I.e. generate a form using whatever server side language you want, and when you submit the form it should do what you want it to do. If you have a form that works without javascript you have the confidence that it'll always work if the js breaks.
Make it work better/ Progressive Enhancement
There look to be 2 or 3 requirements for your js - treat them all individually:
1. The form should show only one input at a time
E.g. with markup like this:
<form id="myForm" method="post">
<legend>My Awesome Form</legend>
<div class="question">
<label for="x">X</label>
<input name="x" id="x">
</div>
<div class="question">
<label for="y">Y</label>
<input name="y" id="y">
</div>
<div class="question">
<label for="z">Z</label>
<input name="z" id="z">
</div>
<div class="submit"><input type="submit" value="Submit"></div>
</form>
Use some js like this:
$('.question', '#myForm').not(':first-child').hide();
$('input', '#myForm').change() {
var div, next;
div = $(this).parent();
next = div.next();
if ($(this).val() && next.length) {
parent.hide();
next.show();
}
});
Which would show only one of the question divs at a time, and show the next one (if there is a next one) when the input is filled.
2. Validate user input
To validate the user input, create a function that does that for you, returning true/false as appropriate and hook that into your js so that it doesn't continue if the input value is deemed invalid:
validate(field, input) {
var valid = false;
// implement your logic here to validate input
if (valid) {
return true
}
return false;
}
$('input', '#myForm').change() {
var div, next;
if (!validate($('this').attr('name'), $(this).val()) {
return;
}
div = $(this).parent();
next = div.next();
if ($(this).val() && next.length) {
parent.hide();
next.show();
}
});
That will prevent the user from moving onto the next input, if the current one has an invalid value.
3. Submitting the form by ajax
Clicking submit should send the form data to the server, in (almost) the same ways as submitting the form normally. the only difference should be that it response with either a json response that you parse, or a snippet of html that you dump at the end of the page:
$('#myForm').submit(function(e) {
e.preventDefault();
$.ajax({
type: "POST",
url: $(this).attr('action'),
data: $(this).serialize(),
success: function(data, textStatus, jqXHR) {
// handle success response
},
error: function(jqXHR, textStatus, errorThrown)) {
// show the user an error
}
});
});
All of the js written here is untested, it should give you some ideas about how to tackle each aspect of what you want to do - of course, for more information of any particular method refer to the docs.
All of this can be done with jQuery, you shouldn't need any additional JS tools.
Since you have a lot of functionality to build out, I'm not going to go into details. However, I can provide some insight into how to go about each step of your process.
1.) Thats fine.
2.) Thats fine too, you just need one html page to accomplish this.
3.) I would recommend having all forms created in HTML with a CSS of display none. Then as the user progresses through, you can use .show() to "show" the hidden elements.
4.) Probably going to want to have a "next" button of some kind outside of your form. Use .click() To trigger a function that does whatever form validation you require on the value of the input form field. You can use .next() to cycle through your form inputs.
5.) If you want a browser scroll use scrollTop or the jQuery ScrollTo Plugin. If your just looking to move things on the screen and not truely scroll, use .animate()
6.) You will have to set the value on the fly as a user progresses. So use .change() to do the detection.
7.) Before submitting, run your validator on all the fields again to ensure you have all correct data. You'll want to use .ajax() to make the request to your service and prevent default on the actual form submit. Take the response you get back from the service and format the information accordingly.
That should give you insight on how to accomplish your project. Good Luck!

Disable required validation by JavaScript

I have a create form to create an object.
The create model has some properties that are only visible (.hide, .show()) if a checkbox is checked and that are marked required (by Attribute in Model).
Unfortunatly when the checkbox is not checked, the required validation is performed on the properties hidden.
How can I disable the required validation for this properties?
I tried setting the data-val property of the input element to false but this does not work.
Some an idea?
Thanks in advance
Tobias
UPDATE:
Here is the java script code. The data-val property is set correctly to false. it seems that validation does not care of this property. there is also the data-val-required attribute but there is a text i could not backup.
$(function () {
$("#MyCheckbox")
.change(function () {
if (this.checked) {
$("#divWithChildProperties [data-val]").attr("data-val", true);
$("#divWithChildProperties ").show();
}
else {
$("#divWithChildProperties [data-val]").attr("data-val", false);
$("#divWithChildProperties ").hide();
}
})
});
I've handled cases like this with a custom Validation Attribute. Instead of using the Required attribute for properties you could make a RequiredIf attribute and make some of your properties required only if another property is a certain value.
Here is a post about creating an attribute like this (the example in the middle of the page under the 'A more complex custom validator' section): http://www.devtrends.co.uk/blog/the-complete-guide-to-validation-in-asp.net-mvc-3-part-2
If your checkbox represents a property in your model this should work fine.
If you don't want to handle this with a new validation attribute you will have to do a few more things than just change the data-val attribute to false. When jQuery validate first parses your form it stores values in the form's data. So simply changing data-val isn't enough. You will additionally have to remove the stored validation data and reparse the form. Here's an example:
// Do this after you've removed/modified the data-val attribute
$('selector for your form').removeData('unobtrusiveValidation');
$('selector for your form').removeData('validator');
$.validator.unobtrusive.parse('selector for your form');
You can use following JQuery to remove all validation rules of your element
$('#ElementId').rules('remove');
Same way you can use class name like,
$('.ElementClassName').rules('remove');
If you want to remove specific rule, do like this
$('#ElementId').rules('remove', 'required');
The unobtrusive javascript plugin provided by MVC doesn't process the data properties on the fly. Instead, it parses the results on document ready and caches them.
Try calling $.validator.unobtrusive.parse(myForm) on your form after modifying the property in question to see if it gives you expected results.
Unobstrusive validation looks for this attribute data-val="true"
I guess, that if you do a $('#mycheckbox').data('val','false'), the validation will skip a item with that id.
Probably there is a more appropriate way to do it, but if not, take this.
cheers.
There are many ways to disable unobtrusive validation in Javascript but most of them seems a bit hackish...
Recently found that you can do it with submit button. Check this link for info
http://www.nitrix-reloaded.com/2013/09/16/disable-client-side-validation-on-a-button-click-asp-net-mvc/
//this
<script type="text/javascript">
document.getElementById("backButton").disableValidation = true;
</script>
//or this
<input type="submit" name="backButton" value="Back"
title="Go back to Prev Step" disableValidation="true" />
//or this
<input type="submit" name="backButton" value="Back"
title="Go back to Prev Step" class="mybtn-style cancel" />
Another way that is more flexible but more complicated : you can disable unobtrusive validation by setting the data-val attribute to false. But there is a trick...
Unobtrusive validation data is cached when the document is ready. This means that if you have data-val='true' at the beginning and that you change it later on, it will still be true.
So, if you want to change it after the document is ready, you also need to reset the validator which will erase the cached data. Here is how to do it :
disableValidation: function () {
//Set the attribute to false
$("[data-val='true']").attr('data-val', 'false');
//Reset validation message
$('.field-validation-error')
.removeClass('field-validation-error')
.addClass('field-validation-valid');
//Reset input, select and textarea style
$('.input-validation-error')
.removeClass('input-validation-error')
.addClass('valid');
//Reset validation summary
$(".validation-summary-errors")
.removeClass("validation-summary-errors")
.addClass("validation-summary-valid");
//To reenable lazy validation (no validation until you submit the form)
$('form').removeData('unobtrusiveValidation');
$('form').removeData('validator');
$.validator.unobtrusive.parse($('form'));
},
You don't need to reset all the messages, input styles and validation summary to be able to submit the form but it's useful if you want to change the validation after the page is loaded. Otherwise, even if you change the validation, the previous error messages will still be visible...
The default DataAnnotationsModelValidatorProvider adds a Required attribute to all value types. You can change this behavior by adding the code in this answer.
You could implement a custom validator like "RequiredIf".
That will keep your model design quite obvious (unlike client-side-only solutions proposed). This allows you to keep the validation logic separate from display logic (that's what MVC is all about).
See this answer : RequiredIf Conditional Validation Attribute
and ultimately that blog post : Conditional Validation in ASP.NET MVC 3
cheers!

Categories

Resources