I am using the jquery validation plugin and want to use the errorPlacement function to add error messages to the fields title attribute and display just a ✘ next to the field.
This works great when the form is submitted with the submit button but when any of the following events are triggered: - onfocusout - click - onkeyup
The validation checks are run but it skips the errorPlacement function and adds the full error message after the field, like the default behaviour.
I am using the following code:
$("#send-mail").validate({
debug: true,
// set this class to error-labels to indicate valid fields
success: function(label) {
// set text as tick
label.html("✔").addClass("valid");
},
// the errorPlacement has to take the table layout into account
errorPlacement: function(error, element) {
console.log("errorPlacement called for "+element.attr("name")+" field");
// check for blank/success error
if(error.text() == "")
{
// remove field title/error message from element
element.attr("title", "");
console.log("error check passed");
}
else
{
// get error message
var message = error.text();
// set as element title
element.attr("title", message);
// clear error html and add cross glyph
error.html("✘");
console.log("error check failed: "+message);
}
// add error label after form element
error.insertAfter(element);
},
ignoreTitle: true,
errorClass: "invalid"
});
Your problem is that the plugin only calls the errorPlacement
function once for each element which is validated. Namly when the error label for the element is first created. Afterwards the plugin just reuses the already present label and just replaces the html inside (or hides the error label if the element is now valid). That's why your cross gets removed and the actual error message is shown.
Just to make sure the flow of the plugin is clear.
errorPlacement
functionlabel.html(message)
instead of removing old label and readding itSo you see your problem is a kind of optimization the plugin does to save some unnecessary inserts/removes of error labels. Which makes sense too.
You can check what I said by looking at the validation-plugin-sourcecode
jquery.validate.js v1.6 check in function showLabel
lines 617-625 for the relevant pieces.
A possible solution could be to additional provide a custom showErrors
callback which solves the problem with brute force.
Something along the lines of
$("#send-mail").validate({
...
showErrors: function(errorMap, errorList) {
for (var i = 0; errorList[i]; i++) {
var element = this.errorList[i].element;
//solves the problem with brute force
//remove existing error label and thus force plugin to recreate it
//recreation == call to errorplacement function
this.errorsFor(element).remove();
}
this.defaultShowErrors();
}
...
});
Maybe there is a cleaner solution to this but this should do it and give you time to investigate a better solution.
Thanks jitter,
I done some digging around and found the same problem.
I managed to get it working by "hacking" the showLabel function in the jquery.validation.js. It's not pretty but works.
Overriding the showErrors function option would prevent me from having to change the plugin code so I will take a look.
Here is the code I used for the showLabel method:
showLabel: function(element, message) {
// look for existing error message
var label = this.errorsFor( element );
// existing error exist?
if (label.length) {
// refresh error/success class
label.removeClass().addClass( this.settings.errorClass );
// check if we have a generated label, replace the message then
label.attr("generated");
// is message empty?
if(!message)
{
// add tick glyph
label.html("✔");
// wipe element title
$(element).attr('title', message)
}
else
{
// clear error html and add cross glyph
label.html("✘");
// update element title
$(element).attr('title', message)
}
// && label.html(message);
}
else {
// create label
label = $("<" + this.settings.errorElement + "/>")
.attr({"for": this.idOrName(element), generated: true})
.addClass(this.settings.errorClass)
.html(message || "");
if ( this.settings.wrapper ) {
// make sure the element is visible, even in IE
// actually showing the wrapped element is handled elsewhere
label = label.hide().show().wrap("<" + this.settings.wrapper + "/>").parent();
}
if ( !this.labelContainer.append(label).length )
this.settings.errorPlacement
? this.settings.errorPlacement(label, $(element) )
: label.insertAfter(element);
}
if ( !message && this.settings.success ) {
label.text("");
typeof this.settings.success == "string"
? label.addClass( this.settings.success )
: this.settings.success( label );
}
this.toShow = this.toShow.add(label);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With