Hi,
I am using Jquery Validation 1.4.2 -http://docs.jquery.com/Plugins/Validation. In my forms, I require both the error message that is returned by Jquery; and an image showing the field is valid or invalid.
I have a three column layout for the form, in a table (hey - a form is tabular!), where the 1st column is the label, the second contains the input ( or select/radio buttons or whatever). The Jquery validation message is added automagically to this cell. In the last cell there is a set to display a notification valid/error/not set image as the background.
Slightly complicating this is that I have several forms, and certain of them have more than one input per line - eg a date field which has three drop-downs for day, month , year. I want only one image to display depending on if all three are valid, all three are unset or one or more is invalid.
I therefore added a custom invalidHandler on the validate call, which gets a list of all "required" elements within the form, and then does the following:
Get this element's parent (this will be a TD tag) Get the above TD tags' next sibling - this is the TD tag in which the notification image appears. Get all child elements that are "input" (in the Jquery validation, :input covers INPUT, SELECT, RADIO, CHECKBOX, TEXTBOX tags) Then - - If the current element has class "valid" AND no siblings have class "error", set the notification image parent TD to class "valid" - If the current element has class "error" OR any siblings have class "error", set the notification image parent TD to class "error" - If the current element's class has not been set, remove the notification image parent TD class
This all seems to work fine if I apply to individual elements, but when adding to the whole form - even though error messages and error classes are set, the validate() call responds that the form is indeed valid, when it is not.
The code is not too clear - and I am certainly passing around too many strings when I should pass Jquery objects, but....
Ideas welcome - I must somehow be either triggering or bypassing the valid() call with the addition of the invalidHandler
/* Form validation error images ----------------------------------------------------------- */
function setErrorImageSingle(formId) {
var formElements = $('#' + formId + " :input.required");
formElements.change(setIndividualErrorImage);
}
function setErrorImageAll(formId) {
var formElements = $('#' + formId + " :input.required");
formElements.each(setIndividualErrorImage);
}
function setIndividualErrorImage() {
var form = $(this).parentsUntil('form').parent();
// get the class - we are looking for 'valid' or 'error' or absence of those
var isValid = form.validate().element('#' + $(this).attr('id')); // <-- problem could be on this line, where I call validate() on an element?
var notificationEl = $(this).parent().parent().children(":last");
var currentParent = $(this).parent();
var siblingCount = currentParent.children(":input").length; // only input and/or selects in the same parent.
var siblingErrorCount = currentParent.children(".error:input").length;
var siblingValidCount = currentParent.children(".valid:input").length;
// test for existence of class, plus NO siblings must have opposite class. Additional logic in first case
// as the jquery validation only adds error/valid class on validation; we must make sure that all siblings are tested.
// alert("I have \n" + siblingCount + " siblings (incuding me)\n" + siblingErrorCount + " are errors,\n" + siblingValidCount + " are valid");
//
switch (true) {
case ($(this).hasClass('valid') && siblingErrorCount == 0):
notificationEl.addClass('valid');
notificationEl.removeClass('error');
break;
case ($(this).hasClass('error') || siblingErrorCount > 0):
notificationEl.removeClass('valid');
notificationEl.addClass('error');
break;
default:
notificationEl.removeClass('valid');
notificationEl.removeClass('error');
break;
}
};
/* Form validation error images ----------------------------------------------------------- */
var RegisterForm = $('#RegisterForm'); if (RegisterForm.length > 0) { // setErrorImageSingle("RegisterForm"); // setErrorImageSingle tells the individual form elements to listen for onchange events. It works, is commented out to text the invalidHandler problem RegisterForm.validate({ submitHandler: function(form) { alert("valid form? " + $(form).valid()); // <-- PROBLEM IS HERE - always returns true????? } , invalidHandler: function(form, validator) { setErrorImageAll("RegisterForm"); // loops through the form elements testing for invalid. } }); }
If I remove the invalidHandler, the form performs as expected (is, will not submit due to invalid input) but the notification messages are not added; as the form elements have not had their onchange event fired.
I looked at this but could not recreate with an example. Did you ever find a solution?
It is on hold while I get more urgent things done. Thanks for looking anyway.
I expect to be on it next week, early on, so will post what i find. I imagine it is a silly error, I just cant see it. Perhaps a few days away from it will help.
OK. Problem solved, albeit after much frustration, and indeed throwing in more complexity in the way of AJAX.
When using both the Validation and the Ajax submit functionality of Jquery Form plugin,http://www.malsup.com/jquery/form/#getting-started it is imperative that the validation is tested in the "beforeSubmit" handler. I don't really see the use of the invalidHandler, although I expect that should beforeSubmit return false, the invalidHandler will be called correctly.
eg
// --------------------------------------------------------------------- // set up ajaxFormOptions var ajaxFormOptions = { beforeSubmit: showSpinner , submitHandler: ajaxSubmitForm , success: hideSpinner , target: '#popInModalForm' } // --------------------------------------------------------------------- // set up the callback functions:
function showSpinner(formData, jqForm, options) { $(jqForm[0]).mask(Resource.LoadingSpinnerText); // add a "loading" message setErrorImageAll(jqForm); // <-- this line adds the validation images I wanted in the 1st place if ($(jqForm).valid()) { return true; // <-- form is ok, all required data is there. } $(jqForm[0]).unmask(); // hide the "loading" message return false; //<-- Make sure you return false if invalid!! } function hideSpinner(responseText, statusText, xhr, jqForm) { $(jqForm[0]).unmask(); // hide the "loading" message, form submission is complete } function ajaxSubmitForm(form) { $(form).ajaxSubmit(); }
// --------------------------------------------------------------------- // finally register the plugins $('#RegisterForm').ajaxForm(ajaxFormOptions); $('#RegisterForm').validate();
// ---------------------------------------------------------------------
This then ensures that
a) the validation works, and my extra images are shown, and b) more importantly, the form does not submit when it is invalid, and c) even more importantly, the form does not submit itself twice (as it was doing, once Ajax and once regular form post)
Seehttp://www.chrillo.info/2008/10/14/jquery-ajaxform-and-validate-with-ajaxsubmit/