jQuery Validation Plugin:在onfocusout,keyup和click时调用errorPlacement函数

时间:2010-03-08 10:27:25

标签: javascript jquery forms validation

我正在使用jquery验证插件,并希望使用errorPlacement函数将错误消息添加到字段title属性,并在字段旁边显示一个✘。

当使用提交按钮提交表单但触发以下任何事件时,此方法很有用:   - onfocusout   - 点击   - onkeyup

运行验证检查,但它会跳过errorPlacement函数并在字段后面添加完整的错误消息,就像默认行为一样。

我使用以下代码:

$("#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"
});

2 个答案:

答案 0 :(得分:17)

您的问题是该插件仅为每个经过验证的元素调用errorPlacement函数一次。 Namly首次创建元素的错误标签时。之后,插件只重用已存在的标签,只是替换内部的html(如果元素现在有效,则隐藏错误标签)。这就是为什么你的十字架被移除并显示实际的错误信息。

只是为了确保插件流畅通。

  1. 元素(尚无错误标签)
  2. 元素在某些时候得到验证
  3. 插件会创建错误标签并调用errorPlacement函数
  4. 元素“cross”(标题中的错误消息)
  5. 元素获得焦点,你改变了一些东西
  6. 插件重新验证元素
  7. 看到错误标签已经创建(并已放置)
  8. 插件只需调用label.html(message),而不是删除旧标签并将其读取
  9. 所以你看到你的问题是插件为保存一些不必要的插入/删除错误标签而做的一种优化。这也是有道理的。

    您可以通过查看validation-plugin-sourcecode

    来查看我说的内容

    jquery.validate.js v1.6检查函数showLabel第617-625行的相关部分。


    一种可能的解决方案是另外提供一个自定义showErrors回调,它可以用暴力解决问题。

    的内容
    $("#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();
        }
    ...
    });
    

    也许有一个更清洁的解决方案,但这应该做,并给你时间来研究更好的解决方案。

答案 1 :(得分:1)

感谢抖动

我做了一些挖掘并发现了同样的问题。

我设法通过“破解”jquery.validation.js中的showLabel函数来实现它。它不漂亮但是很有效。

覆盖showErrors函数选项会阻止我不得不更改插件代码,所以我会看看。

以下是我用于showLabel方法的代码:

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