如何作为本机验证事件流的一部分调用自定义约束验证?

时间:2014-01-08 18:10:15

标签: javascript html5 forms validation

  • 以下内容基于使用Chrome 31进行测试
  • TL; DR:this fiddle中的代码如何处理尝试提交,但this one中的代码不适用于手动调用?有更好的方法吗?

在回答a question asking for a way of validating an <input type="file"> against its accept attribute时(原生行为将与生成的文件对话框一起使用,默认情况下会显示过滤器,但不会强制执行),我想看看有哪些选项可用于将此自定义验证集成到HTML5的脚本Constraint validation

我对API的初步略读使我覆盖了本机checkValidity方法,相信只要浏览器认为适合验证代码(jsFiddle),就会默认调用它。 :

void function enhanceFileInputTypeValidityCheck(){
    var inputPrototype      = document.createElement( 'input' ).constructor.prototype;
    var nativeCheckValidity = inputPrototype.checkValidity;

    // This is my custom validation function
    function validateFileInputType( input ){
        var MIMEtype = new RegExp( input.accept.replace( '*', '.\*' ) );

        return Array.prototype.every.call( input.files, function passesAcceptedFormat( file ){
            return MIMEtype.test( file.type );
        } );
    }

    // My attempt at getting the behaviour to happen 
    inputPrototype.checkValidity = function enhancedCheckValidity(){
        if( this.type === 'file' &&  this.accept && this.files && this.files.length ){
            if( !validateFileInputType( this ) ){
                this.setCustomValidity( 'Please only submit files of type ' + this.accept );

                return false;
            }
        }

        return nativeCheckValidity.apply( this );
    }
}();

这有效地增强了checkValidity在我的条件未满足时返回false,并且如果属于,则属于原生行为,但setCustomValidity未按预期工作:不会抛出任何异常,但也不会显示任何错误消息。至关重要的是,我return false checkValidity并不会阻止表单提交。

经过一番摆弄后,我最终得到了这个事件处理程序,它与上面发布的代码一起最终达到了预期目标 - 即根据自定义标准阻止提交并反馈给用户(jsFiddle):

$( 'input' ).on( 'change input', function( event ){
    this.checkValidity();
} );

我对如何发生这种情况感到困惑:根据记录事件类型,change将执行checkValidity,但不会显示消息;同时注册提交表单 实现我的setCustomValidity,但不会记录事件类型:但是暗示这是一个input事件,因为那是唯一的处理程序正在侦听的其他事件 - 但是(这是真正怪异的地方),从change取消绑定(无论如何都没有工作)只留下input触发我的强制回调doesn't prevent submission at all anymore

我仍然对将自定义验证绑定到本机验证流程的'正确'方式感到茫然,因为绑定到changeevent以触发这些事件都没有发生时的预期行为实际上发生的事情实际上似乎太过于苛刻而无法用作。

用于解释以下任何内容的奖励积分:

  • 在空输入上调用console.log时,为什么我的自定义验证checkValidity没有得到任何反馈?
  • 为什么我从绑定到console.log&amp;&amp;的事件处理程序中的input得到任何反馈? change
  • 如何执行代码作为change事件的回调不会触发setCustomValidity
  • 什么事件 - 如果不是input - 实际上是在触发我的setCustomValidity
  • 我是否可以在不覆盖checkValidity的情况下生成相同的所需最终结果?

3 个答案:

答案 0 :(得分:3)

据我所知,checkValidity方法调用浏览器的内部验证,而不是浏览器的内部验证调用。因此,如果您覆盖它,浏览器将不会注意到或关心。

根据我的经验,实现自定义有效性所需的一切是绑定到change事件,然后使用正确的值调用setCustomValidity。例如,

myinput.addEventListener('change', function(e) {
    if ( ! myCustomValidityCheck() )
        this.setCustomValidity( 'Uh oh, that didn\'t work!' );
    else
        this.setCustomValidity( '' );
})

Whimsical JSFiddle example

答案 1 :(得分:0)

以下是您的问题的解决方案http://jsfiddle.net/trixta/E7VtD/

  1. 使用更改而不是输入事件。输入事件很好,但不适用于输入[type = file]。
  2. 您不应该覆盖checkValidity
  3. 在dom ready +每次更改时使用setCustomValidity
  4. 使用reportValidity(如果有)报告错误或通过单击提交按钮来模拟reportValditity
  5. 这是使setCustomValidity更简单的简单方法:

    //setCustomValidity is stupid so we improve by adding setCustomValidityRule
    $.fn.setCustomValidityRule = function (type, rule) {
        var testRule = function () {
            //only if it's valid or we have set the message our own
            if ($(this).is(':valid') || $.data(this, 'customErrorType' + type)) {
                var message = rule(this);
                this.setCustomValidity(message);
                if (message) {
                    $.data(this, 'customErrorType' + type, message)
                } else {
                    $.removeData(this, 'customErrorType' + type);
                }
            }
        };
        return this
        //invoke initially
        .each(testRule)
        //and on every change
        .on('customchange.customerror' + type + ' change.customerror' + type, testRule);
    };
    

    这是一种使reportValidity在当前浏览器中工作的方法:

    $.fn.reportValidity = function () {
        return this.each(function () {
            var form;
            if (this.reportValidity) {
                this.reportValidity();
            } else {
                form = $($.prop(this, 'form')).add(this).filter('form');
                //checkvalidity is obtrusive sometimes so we use :invalid
                if($(':invalid', form).length){
                $('<input type="submit" />')
                    .css({
                        position: 'absolute',
                        left: '-99999px'
                    })
                    .appendTo(form)
                    .click()
                    .remove();
                }
            }
        });
    };
    

答案 2 :(得分:0)

我会尝试总结一下我的经历:

  1. 应在用户数据输入和表单提交按钮单击上执行自定义验证检查。
  2. 您需要同时使用HTML5表单验证API中的setCustomValiditycheckValidity方法。
  3. 要验证用户数据输入,请在输入字段元素中添加一个input事件侦听器,该侦听器在输入字段上调用setCustomValidity。在setCustomValidity的参数中,您调用一个合适的检查函数,如果用户输入有效则返回空字符串,否则返回约束违规消息。
  4. 要验证表单提交按钮,请单击表单元素上的checkValidity,并仅在返回true时继续提交。
  5. 另请参阅my answer to a similar SO questiontry my example solution