I've implemented the excellent method to use Bootstrap 3's Popovers to show validation error messages, and for the most part it works well - except when it comes to hidden or replaced elements, like Select2 or CKEditor. The popover positions itself correctly on regular elements like input and normal selects, but not a select enhanced by Select 2.
I've created a Fiddle that Sparky fixed so it actually works: http://jsfiddle.net/jemxtthb/4/
$("#noticeSentTo").select2();
var validator = $("#documentAdmin").validate({
debug: true,
ignore: "",
showErrors: function(errorMap, errorList) {
$.each(this.successList, function(index, value) {
return $(value).popover("hide").parents(".form-group").removeClass('has-error').addClass('has-success');
});
return $.each(errorList, function(index, value) {
var _popover;
_popover = $(value.element).popover({
trigger: "manual",
placement: "auto top",
content: value.message,
container: "body",
template: "<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><div class=\"popover-content\"><p></p></div></div>"
});
_popover.data("bs.popover").options.content = value.message;
return $(value.element).popover("show").parents(".form-group").addClass('has-error').removeClass('has-success');
});
}
});
});
Here's a screen capture of what I see within my application:
I've tried using the selector
option on the popovers, but can't figure out how to specify the current element the popover's being applied to (if that's even the right way to do it).
As you can see from my screen capture, the popover appears up and to the far left of the element (in red) it's supposed to be bound to because Select2 is hiding the original select.
UPDATE: Based on @Sparky's suggestion, I've changed it to use errorPlacement
instead of the method I used previously - the only issue now is getting the condition where if it's a hidden element (like Select2 or CKEditor) to provide the Popup to the parent object instead of the element itself (since Popovers cannot work on hidden elements, apparently) - I've put in some debug console.log
code just to make sure the if
statement in the jQuery is firing correctly:
var validator = $("#documentAdmin").validate({
ignore: [],
errorPlacement: function (error, element) {
var lastError = $(element).data('lastError'),
newError = $(error).text();
$(element).data('lastError', newError);
if (newError !== '' && newError !== lastError) {
$(element).popover({
trigger: "manual",
placement: "auto top",
content: newError,
container: "body",
template: "<div class=\"popover\" role=\"tooltip\"><div class=\"arrow\"></div><div class=\"popover-content\"><p></p></div></div>"
});
if (element.is(':hidden')) {
// $(element).next().parents(".form-group").addClass('has-error').removeClass('has-success').popover("show");
$(element).next('span').popover('show').addClass('has-error').removeClass('has-success');
console.log('hidden element');
} else {
$(element).popover("show").parents(".form-group").addClass('has-error').removeClass('has-success');
console.log('normal element');
}
}
},
success: function (label, element) {
$(element).popover("hide").parents(".form-group").removeClass('has-error').addClass('has-success');
}
});
And here's an updated Fiddle: http://jsfiddle.net/jemxtthb/6/
OK - really odd - the Fiddle above actually works as expected! Now I need to figure out why it works in the Fiddle and not my app...
Any help/guidance is appreciated!