jQuery 验证、Select2 和 Bootstrap 3 弹出框 - 如何将弹出框绑定到 Select2 的父元素而不是隐藏的 Select 元素

jQuery Validate, Select2, and Bootstrap 3 Popovers - How to Bind Popover To Select2's Parent Elements Instead of Hidden Select Element

我已经实现了使用 Bootstrap 3 的 Popovers 显示验证错误消息的优秀方法,并且在大多数情况下它运行良好 - 除了涉及隐藏或替换元素时,例如 Select2 或 CKEditor。弹出窗口将自身正确定位在常规元素上,例如输入和普通 selects,但不是由 Select 增强的 select 2.

我创建了一个 Fiddle,Sparky 修复了它,所以它确实有效: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');
        });
        }
    });
});

这是我在应用程序中看到的屏幕截图:

我试过在弹出窗口上使用 selector 选项,但无法弄清楚如何指定应用弹出窗口的当前元素(如果这甚至是正确的方法)。

正如您从我的屏幕截图中看到的那样,弹出窗口出现在它应该绑定到的元素(红色)的最左侧,因为 Select2 隐藏了原始 select.

更新:根据@Sparky 的建议,我将其更改为使用 errorPlacement 而不是我之前使用的方法 - 现在唯一的问题是获取条件,如果它是隐藏元素(如 Select2 或 CKEditor) 以向父对象而不是元素本身提供 Popup(自 Popovers cannot work on hidden elements, apparently 起)- 我已经放入了一些调试 console.log 代码只是为了确保 [= jQuery 中的 18=] 语句正确触发:

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');
    }
});

这是更新后的 Fiddle:http://jsfiddle.net/jemxtthb/6/

好的 - 真的很奇怪 - 上面的 Fiddle 实际上按预期工作!现在我需要弄清楚为什么它在 Fiddle 而不是我的应用程序中工作...

任何 help/guidance 不胜感激!

查看 JavaScript 控制台中的错误并修复您的 jsFiddle 中的以下内容...

  1. 如果 select 元素预加载了值,则没有必要进行验证。换句话说,如果每个 option 已经包含一个值,或者是否存在一个 option 和一个具有 selected 属性的 value,则无需验证。通常,第一个 option 包含 value="".

    <option value="">Please select<option>
    
  2. 您的 Bootstrap 脚本文件出现 404 错误。 CDN URL 已损坏。

  3. 不关键,但应该是ignore: [],而不是ignore: ""

  4. 您在调试控制台中收到 "no 'name' assigned" 错误,因为 Select2 创建的隐藏 input 元素不包含name 属性。现在这显然不是问题,但当页面上有更多元素时可能会成为问题。 jQuery 验证插件要求所有要验证的元素都包含一个 name 属性。

演示:http://jsfiddle.net/jemxtthb/4/


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.

您不应将 showErrors 用于工具提示,因为此回调函数通常用于生成所有消息的列表,例如表单顶部的摘要。 "Gets the map of errors as the first argument and an array of errors as the second."

相反,您需要将工具提示插件与 jQuery 集成,使用其 errorPlacement and success 回调函数进行验证;这会将单个 pending 错误消息放入单个工具提示中。此集成还取决于您的弹出窗口插件的可用选项...比如您可以动态更改工具提示中的文本吗?你能 dynamically/programmatically show/hide 他们等等吗?

然后 errorPlacement 中,当元素被 Select2 等隐藏时,您可以有条件地定位某些元素以调整位置

类似这样的东西...

$("#documentAdmin").validate({
    ignore: [],
    errorPlacement: function (error, element) {
        // put text of error into tooltip with $(error).text()
        // conditional placement of the tooltip
        // show the tooltip
    },
    success: function (label, element) {
        // hide the tooltip
    },
    // any other options
});

I'm using the ToolTipster jQuery plugin like this.

事实证明,上面的代码从一开始就工作正常 - 在@Sparky 修复我的 Fiddle 之后,弹出窗口工作正常,相对于 Select2 的父元素定位自己。

这样做的好处是@Sparky 建议使用 errorPlacement 而不是我最初使用的方法,后者可以更好地控制单个元素的错误消息放置方法。

我目前正在调查(并怀疑)罪魁祸首是我用于侧边栏的 offcanvas 插件 - 我没有将其包含在 Fiddle 中,因为我想保留 Fiddle 问题尽可能简洁,不要使事情复杂化。当我发现问题所在时,我会更新它。如果有人有兴趣在 Bootstrap 3 Popovers 中实现这种验证错误的方法,我会使用我发布的第二个 Fiddle 中的代码。