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.
element (no errorlabel yet)
element gets validated at some point
plugin creates error label and calls errorPlacement function
element "cross" (error message in title)
Element gets focus and you change something
plugin revalidates element
Sees that error label was already created (and placed)
plugin just calls label.html(message) instead of removing old label and readding it
So 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);
}
Related
Several similar question exist, but after fighting with this for a day or so I feel the need to ask because the vast majority of the answers refer to adding event handlers to elements.
I am not interested in adding an event handler to the elements in question, rather I am interested in adding additional dynamic content to dynamically generated content.
The app works thusly:
load a modal form dynamically upon the click of a static element (working properly)
function loadModal(target,modalId) {
console.log("==================> loadModal() Entry");
$.ajax({
type: "GET",
url: 'http://localhost/retrieve-modal/'+modalId,
success : function (text) {
$("#"+modalId)[0].innerHTML = text;
modalSaveIntercept($("#"+modalId)[0])
},
failure : function (e) {
console.log("something is wrong");
}
})
}
Then I have a save interceptor that overrides the default save behavior of my form here this is also working properly, (I suspect because I am loading this event handler at the time of loading the modal)
function modalSaveIntercept(eventTarget) {
if(eventTarget.hasChildNodes()) {
eventTarget.childNodes.forEach(function(e) {
if(e.tagName == "FORM") {
console.log("found the form: " + e.id + " applying save override listener");
$("#"+e.id).submit(function(event){
event.preventDefault();
submitForm(e);
});
modalSaveIntercept(e)
}
});
}
}
the above attaches a listener to the form loaded into my modal and rather than firing the default behavior of a Save button click, it fires my submitForm() function which is here:
function submitForm(form) {
let payload = constructPayloadFromFormData(form);
validate(payload).then(function(v) {
console.log("response Data:");
for(let p in v) {
if(v.hasOwnProperty(p)) {
constructInvalidFeedbackForProperty(p,v[p])
}
}
});
}
this function constructs a payload from the form data (working fine) then executes another ajax call inside of validate() - I wait for the return call from ajax and then iterate through an array of validation data to confirm the form's validity. However, here is where the problem is:
function constructInvalidFeedbackForProperty(prop,e) {
let el = $("#" + "ic-role-" + prop);
console.log(el);
el.append("<div class=\"invalid-feedback\">problem</div>");
}
the problem is the append - I cannot seem to fire that method. I can select the element as the console.log(el) writes to the log the correctly identified element in my dom.
What am I doing wrong?
I have created a contrived jsfiddle for a sample of the problem. I actually believe it may be that an input field is not something you can append to... perhaps? https://jsfiddle.net/jtango/xpvt214o/987051/
Okay, I messed around with your fiddle a bit. If you inspect the input element that is created you can see that your append does work. It's just not displaying. If you are trying to edit what is in the input box then you must use val()
Here is a copy of your fiddle that will display inside the input:
$("#top").on("click", function(){
$("#form").append("<label>some label: </label><input type=\"text\" id=\"myinput\">");
});
$("#btm").on("click",function(){
$("#myinput").val("<div>I will not appear</div>");
});
As your shared https://jsfiddle.net/jtango/xpvt214o/987051/ It will not appear, this is wrong way to append any HTML element inside "input box" or any of form elements. it should allow to set only new attribute or value.
check screenshot: https://i.stack.imgur.com/4FBgn.png
So verify your below code if it's similar then it will not work:
let el = $("#" + "ic-role-" + prop);
console.log(el);
el.append("<div class=\"invalid-feedback\">problem</div>");
I am currently working on jQuery validation; the current code I have was working fine, I am getting the number of error count. But I am not getting when the user enter the value in the corresponding field the error count has to detect one by one.
For example if I have 5 fields are not entered by the user it should say You have missed 5 fields. Please fill before submitted when all fields are entered the error field has to disable. And I need to highlight the label of the radio input when nothing is selected. Moreover I am trying to change my mandatory star from black to red. That is also not happening.
Here is my jQuery code.
$(document).ready(function () {
$("#basicForm").validate({
invalidHandler: function(event, validator) {
var errors = validator.numberOfInvalids();
if (errors) {
var message = errors == 1
? 'You missed 1 field. It has been highlighted'
: 'You have missed ' + errors + ' fields. Please fill before submitted.';
$("#error_message").html(message);
$(".error_msge").show();
$("div.error").show();
$("#error_message").addClass("error_msge");
} else {
$("div.error").hide();
$("#error_message").removeClass("error_msge");
}
},
errorPlacement: function(error, element) {
},
onkeyup: false,
highlight: function(element) {
$(element).addClass('errRed');
$(element).addClass('text-error-red');
},
unhighlight: function(element) {
$(element).removeClass('errRed');
$(element).removeClass('text-error-red');
},
rules: {
txt_Fname: "required",
txt_lname: "required",
txt_Mfname: "required",
txt_Mlname: "required",
txt_Pptnum: "required",
txt_Pi: "required",
txt_dob: "required",
txt_Idt:"required",
txt_Epdt:"required",
sel_ms:"required",
ipt_nation:"required",
ipt_countryres:"required",
sel_rg:"required",
sel_sem:"required",
ipt_acdem:"required",
gender:"required"
}
});
});
Here is the Fiddle link.
You have lots of issues and I strongly recommend that you review the documentation.
But I am not getting when the user enter the value in the corresponding field the error count has to detect one by one for example If I have 5 fields are not entered by the user it should say You have missed 5 fields.
You have used the wrong option. The invalidHandler only fires on an invalid form, so when there are zero errors your function will never be called and it will be stuck on show "1 error". Use the showErrors option instead.
showErrors: function (errorMap, errorList) {
var errors = this.numberOfInvalids();
if (errors) {
var message = errors == 1 ? 'You missed 1 field. It has been highlighted' : 'You have missed ' + errors + ' fields. Please fill before submitted.';
$("#error_message").html(message);
$(".error_msge").show();
//$("div.error").show(); // superfluous
//$("#error_message").addClass("error_msge"); // superfluous
} else {
$(".error_msge").hide();
//$("div.error").hide(); // superfluous
//$("#error_message").removeClass("error_msge"); // superfluous
}
// ensures that highlight/unhighlight will function
this.defaultShowErrors();
},
Please fill before submitted. when all fields are entered the error field has to disable.
You forgot to hide the error message box when there are no errors: $(".error_msge").hide() was missing
And I need to highlight the label of the radio input when nothing is selected.
You need a conditional inside the highlight and unhighlight functions that will take care of this when the element is a radio.
highlight: function (element) {
if ($(element).is(':radio')) {
$(element).siblings('label').addClass('errRed');
} else {
$(element).addClass('errRed');
}
$(element).prev('span.required-star').addClass('text-error-red').removeClass('text-error-black');
},
unhighlight: function (element) {
if ($(element).is(':radio')) {
$(element).siblings('label').removeClass('errRed');
} else {
$(element).removeClass('errRed');
}
$(element).prev('span.required-star').addClass('text-error-black').removeClass('text-error-red');
}
I also moved the code for the asterisks in here since you want them to toggle color individually.
More over I am trying to change my mandatory star from black to red.
Your CSS technique is flawed. You are trying to select everything with the "black" class and simply add a "red" class, leaving you with two classes each with a different color. Instead, you need to replace one class with the other class. Something like this...
$(".required-star").removeClass("text-error-red").addClass("text-error-black");
You need to programmatically trigger validation using the .valid() method when you use the date-picker...
$('.ipt_Field').on('change', function() {
$("#basicForm").valid();
});
You do not need the messages option. Since you are suppressing all of the messages, it's pointless.
Also do not leave the errorPlacement function empty. Put a return false inside.
errorPlacement: function() {
return false; // suppress error messages.
}
DEMO: http://jsfiddle.net/k5wxtmpL/
I would like to add custom error replacement using jquery validation plugin (http://jqueryvalidation.org/documentation/) I would like to do custom error replacement like click here
$(function() {
//simple example 1
//click event for first button
$("#form1").validate({
errorPlacement: function(error, element) {
if (element.attr("name") == "business_email" ) {
$("#bus_email").css('color',"#f42156");
$("#busp_email").removeClass("field_validation_error hidden");
$("#busp_email").addClass("field_validation_error");
}
},
rules: {
business_email: "required"
},
messages: {
business_email: "Please enter your firstname"
}
});
});
https://jsfiddle.net/fr0dc2es/7/
With this code you can get custom replacement message and act on #bus_email:
$(function() {
//simple example 1
//click event for first button
$("#form1").validate({
rules: {
business_email: "required"
},
messages: {
business_email: "Please enter your firstname"
},
errorPlacement: function(error, element) {
if (element.attr("name") == "business_email") {
$("#bus_email").css('color',"#f42156");
$("#busp_email").removeClass("hidden");
$("#busp_email").html(error);
} else {
$("#busp_email").addClass("hidden");
$("#busp_email").html();
error.insertAfter(element);
}
}
});
});
JQueryValidation Documentation
In your JSFiddle, errorPlacement function is being called and jQueryVal is working properly.
However,
Your #busp_email is shown but empty.
Your script logic is incorrect. Why do you remove a class, and add this class right after it? Why don't you hide it?
You don't need to check for every value in errorPlacement. It is not how it works. You shouldn't define a error placement for every input in a predefined error box - you should define a common placement logics by creating dynamic error messages after an input or in a specified place; or by appending an error to the specified alert; but definitely not by checking for every item.
Why default validation error placement is not suitable for you? What do you want to change? Describe it and I will try to help you - now you just provide an invalid code without any explanations.
I have this simple small peace of code which generate an exception : (only in chrome)
Uncaught Error: NotFoundError: DOM Exception 8
Scenario : If a user visited a textbox and didn't put a value , he will be notify when bluring.
And the textbox will be wrapped with a red div. And if he clicks - (in order to put a value) - the red div is removed ( by unwrap the textbox).
So
I have a textbox.
This textbox has a blur handler attched.
When a blur occurs , I'm checking if a value has been entered.
if a value has been entered : everything is ok. nothing is done.
if not :
I alert the user
I wrap the textbox , with a red border
I attach a click event handler so that if the user clicks on the text box (in order to put a value )
the border disappears .
The problem :
When the user was alerted and a red-div wraps the textbox , every time I click on the textbox (in order to put a value) - Im getting the exception ( and obviously things are messed up)
Question :
Why is it happenning , and how can I fix it ?
The code : ( JSBIN )
$("body").on("blur", ".myTb", function () {
if (!$(this).val()) {
alert('you must enter something!');
doWork($(this))
}
});
function doWork(obj) {
var t = $("<div class='divError'/>");
obj.wrap(t);
obj.on('click', function () {
obj.unwrap();
});
}
p.s.:
1) I want to keep the idea of wrapping an element with a red div and to remove it when - user clicks (in order to put a value). (because this is a small part of my plugin which already works like this)
2) There is no problem in FF
3) chrome version : 25.0.1364.97 m
4) jquery: 1.8
I think the problem is, that you wrap the input field multiple times. As soon as you test if the error wrapper already exists, the error is gone:
$("body").on("blur", ".myTb", function () {
if (!$(this).val()) {
doWork($(this));
}
});
function doWork(obj) {
var t = $("<div class='divError'/>"),
hasError = obj.closest('.divError').length;
if(!hasError) {
alert('you must enter something!');
obj.wrap(t);
}
//console.log(obj);
obj.on('click', function () {
console.log(obj);
obj.unwrap();
obj.focus(); // be sure to set focus to the input element
});
}
Updated test is here.
The problem is that the blur event fires when you unwrap the input element. It's safer to use .one() in this case:
function blurOn()
{
$("body").one("blur", ".myTb", function () {
if (!$(this).val()) {
alert('you must enter something!');
doWork($(this));
}
});
}
function doWork(obj)
{
var t = $("<div class='divError'/>");
obj.wrap(t);
obj.one('focus', function () {
obj.unwrap().focus();
blurOn(); // enable blur event handler again
});
}
blurOn();
Demo
I am using requiredFieldValidator for my TextEditor. Using the onValidationError event as given below, i set the title attribute of my cell to the error message so that a tooltip will be displayed as 'This is a required field'.
var handleValidationError = function(e, args) {
var validationResult = args.validationResults;
var activeCellNode = args.cellNode;
var editor = args.editor;
var errorMessage = validationResult.msg
$(activeCellNode).live('mouseover mouseout', function(event) {
if (event.type == 'mouseover') {
$(activeCellNode).attr("title", errorMessage);
} else {
$(activeCellNode).attr("title", "");
}
});
grid.onValidationError.subscribe(handleValidationError);
Successfully, the tooltip is displayed when there is some validation error.
But the problem is When the same cell is given a correct value and validation succeeds, the previous tooltip appears again.
How do I remove that tooltip on successful validation?
I have found a solution for this issue and it works fine.
By going through the slick.grid.js code, i understood that OnValidationError event will be triggered only when the 'valid' value from the validator is false.
My idea was to fire the onValidationError event whenever validator is called i.e on both validation success and failure, and to check for 'valid' value and handle the tooltip according to that value.
STEPS:
In slick.grid.js, I added the trigger for onValidationError event when 'valid' from validator is true also.
(i.e) add the below given code before return statement in if(validationResults.valid) in slick.grid.js
trigger(self.onValidationError, {
editor: currentEditor,
cellNode: activeCellNode,
validationResults: validationResults,
row: activeRow,
cell: activeCell,
column: column
});
2. In the onValidationError event handler of your slickgrid,get the value of the parameter 'valid'. If true, it means validation is success and remove tooltip i.e remove
title attribute for that node. If 'valid' is false, it means
validation has failed and add tooltip.i.e set the title attribute to
error message. By doing this, the tooltip of the previous
onValidationError will not appear on the same node. The code goes as
follows:
grid.onValidationError.subscribe(function(e, args) {
var validationResult = args.validationResults;
var activeCellNode = args.cellNode;
var editor = args.editor;
var errorMessage = validationResult.msg;
var valid_result = validationResult.valid;
if (!valid_result) {
$(activeCellNode).attr("title", errorMessage);
}
else {
$(activeCellNode).attr("title", "");
}
});
Hope this solution will help others for this issue.
HAPPY LEARNING!!!
Rather than editing the slick grid js - I've submitted a request for this change - in the meantime you can subscribe to the following events to remove the previous validation display:
grid.OnCellChange.Subscribe(delegate(EventData e, object a)
{
// Hide tooltip
});
grid.OnActiveCellChanged.Subscribe(delegate(EventData e, object a)
{
// Hide tooltip
});
grid.OnBeforeCellEditorDestroy.Subscribe(delegate(EventData e, object a)
{
// Hide tooltip
});
A much more appropriate way to implement this is to subscribe to the onBeforeCellEditorDestroy event and clean up the state (i.e. clear the tooltip) there.
I wasn't able to determine the current cell in OnBeforeCellEditorDestroy, so I just cleared the title in onCellChange, which fires before onValidationError. For example:
grid.onCellChange.subscribe(function (e, args) {
$(grid.getCellNode(args.row, args.cell)).children("input").attr( "title", "");
});