开发者

jquery.validate plugin - how to trim values before form validation

开发者 https://www.devze.com 2022-12-13 11:17 出处:网络
I\'m using the excellent jquery.validation plugin by Jörn Zaefferer and I was wondering whether there\'s a easy way to automatically trim form elements before they are validated?

I'm using the excellent jquery.validation plugin by Jörn Zaefferer and I was wondering whether there's a easy way to automatically trim form elements before they are validated?

The following is a cut down but working example of a form which validates a email address:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
        "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1" />
    <script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"
           type="text/javascript"></script>
    <script src="http://ajax.microsoft.com/ajax/jquery.validate/1.5.5/jquery.validate.js" 
           type="text/javascript"></script>
    <script type="text/javascript">
        $().ready(function() {
          $("#commentForm").validate({
            rules: {
                email: {
                    required: true,
                    email: true
                }
            }
          });
        });
    </script>
</head>
<body>

  <form class="cmxform" id="commentForm" method="get" action="">
     <label for="cemail">E-Mail:</label><input id="cemail" name="email"
      class="required email" />
     <input class="submit" type="submit" value="Submit"/>
  </form>

</body>
</html>

The problem is that some users are getting confused because they accidently enter some whitespace in their email address, e.g. "test@test.com ". And the form won't submit and has a error message: "Please enter a valid email address.". Non-techy users don't know how to spot whitespace and may just quit the site rather than try to work out 开发者_C百科what they've done wrong.

Anyway, I was hoping I could chain "jQuery.trim(value)" before the validation so the whitespace is removed and the validation error never occurs?

I could use addMethod to build my own email validation function. But I'm sure there's a more elegant solution?


I did this with success.

Instead of:

Email: { required: true, email: true }

I did this:

Email: {
    required: {
        depends:function(){
            $(this).val($.trim($(this).val()));
            return true;
        }
    },
    email: true
}


This code works for me. I haven't used it much so there may be bugs.

It wraps each method and trims the first element which is value.

(function ($) {

    $.each($.validator.methods, function (key, value) {
        $.validator.methods[key] = function () {           
            if(arguments.length > 0) {
                arguments[0] = $.trim(arguments[0]);
            }

            return value.apply(this, arguments);
        };
    });
} (jQuery));

if you're using select2 and validation at the same time, I recommend to put el.val($.trim(el.val())); inside an IF like this: if(el.prop('type') != 'select-multiple'){el.val($.trim(el.val()));}. That way, your jquery validation will behave as expected, and it will let you select multiple items.


Since I want this behavior on all my forms by default I decided to modify the jquery.validate.js file. I applied the following change to onfocusout method:

Original:

onfocusout: function (element, event) {
    if (!this.checkable(element) && (element.name in this.submitted || !this.optional(element))) {
        this.element(element);
    }
}

To:

onfocusout: function (element, event) {
    if (element.tagName === "TEXTAREA" || (element.tagName === "INPUT" && element.type !== "password")) {
        element.value = $.trim(element.value);
    }
    if (!this.checkable(element) && (element.name in this.submitted || !this.optional(element))) {
        this.element(element);
    }
}

I do want to allow spaces at the begging and end of password.

autoTrim could be added as a property to options.


I like the approach by xuser (https://stackoverflow.com/a/10406573/80002), however, I do not like messing with the plugin source code.

So, I suggest doing this instead:

 function injectTrim(handler) {
  return function (element, event) {
    if (element.tagName === "TEXTAREA" || (element.tagName === "INPUT" 
                                       && element.type !== "password")) {
      element.value = $.trim(element.value);
    }
    return handler.call(this, element, event);
  };
 }


 $("form").validate({
    onfocusout: injectTrim($.validator.defaults.onfocusout)
 });


When downloading validator.js, there is a file called additional-methods.js that contains the method "nowhitespace" and "lettersonly" that will strip out any white space in a field.

rules: {
  user_name: {
    required: true,
    minlength: 3,
    nowhitespace: true
  }
}


Add a new jQuery validator method requiredNotBlank. Then apply that function to your elements rather than the default required function. This solution doesn't change the original validator source code, nor does it modify the default required function, nor does it modify the element's value directly.

// jQuery Validator method for required not blank.
$.validator.addMethod('requiredNotBlank', function(value, element) {
    return $.validator.methods.required.call(this, $.trim(value), element);
}, $.validator.messages.required);

// ...
$('#requiredNotBlankField').rules('add', 'requiredNotBlank');


For reference, until I find a more elegant solution, I'm using addMethod as follows:

// Extend email validation method so that it ignores whitespace
jQuery.validator.addMethod("emailButAllowTrailingWhitespace", function(value, element) {
    return (this.optional(element) || jQuery.validator.methods.email.call(this, jQuery.trim(value), element));
}, "Please enter a valid email");

$().ready(function() {
    $("#commentForm").validate({
        rules: {
            cemail: {
                required: true,
                emailButAllowTrailingWhitespace: true
            }
        }
    });
});

Note: this doesn't actually strip the whitespace from the field, it only ignores it. So you need to ensure you perform trim on the server-side before inserting in the DB.


Starting from jQuery Validation plugin version 1.15 a normalizer function is supported. The normalizer can transform the value of an element before validation.

Note that the result of the normalizer is only used for validation. If you would like to update the value of the element you must do so explicitly.

$("#form").validate({
    rules: {
        email: {
            required: true,
            email: true,
            // Optionally disable validation on every key press
            onkeyup: false,
            normalizer: function(value) {
                // Update the value of the element
                this.value = $.trim(value);
                // Use the trimmed value for validation
                return this.value;
            }
        }
    }
});


Pulled the regex from the jquery validator. Just override their email validation.

$.validator.addMethod("email", function(value, element) {
value = value.trim();
return this.optional(element) || /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))$/i.test(value);
}, "Please enter a valid email.");


This is what works for me:

$(':input').change(function() {
    $(this).val($(this).val().trim());
});


Could you not bind the trim to a blur event? Something like...

$("#cemail").blur(function(){
  $(this).val(jQuery.trim($(this).val());
});


Use normalizer, Please check below example

<script src="https://cdn.jsdelivr.net/jquery.validation/1.16.0/additional-methods.min.js"></script>
<script>
  $("#myform").validate({
    rules: {
      field: {
        required: true,
        normalizer: function(value) {
          // Trim the value of the `field` element before
          // validating. this trims only the value passed
          // to the attached validators, not the value of
          // the element itself.
          return $.trim(value);
        }
      }
    }
  });
</script>


I've found that the majority of these are not quite what is needed.

Using the following only fires on form change rather than on key down allowing you to still check on key stroke for the rest of the validation.

It's not as tidy as including it within the plugin, but it's an acceptable compromise.

$('body').on 'change', 'form input[type=text], form input[type=email]',  ->
    $(@).val $.trim($(@).val())


In jquery validation you will find the below code:

required: function( value, element, param ) {

        // Check if dependency is met
        if ( !this.depend( param, element ) ) {
            return "dependency-mismatch";
        }
        if ( element.nodeName.toLowerCase() === "select" ) {

            // Could be an array for select-multiple or a string, both are fine this way
            var val = $( element ).val();
            return val && val.length > 0;
        }
        if ( this.checkable( element ) ) {
            return this.getLength( value, element ) > 0;
        }
        return value.length > 0;
    }

Change the value.length to $.trim(value).length


You can run code before the form is checked like this:

var origCheckForm = $.validator.prototype.checkForm;
$.validator.prototype.checkForm = function() {
    $(this.currentForm).find('.CodeMirror').each(function() {
        if(this.CodeMirror && this.CodeMirror.save) {
            this.CodeMirror.save();
        }
    });

    return origCheckForm.apply(this, arguments);
};

I've used it to save all my CodeMirror instances back to their corresponding texareas. You could use it to trim values instead if you want.


Why not do this?

Validation is occurring after the keyup event. On keyup replace textbox value with its trimmed value (or use a regex to remove any space):

$("#user_name").on("keyup", function(){
    $("#user_name").val($.trim($("#user_name").val()));
});
0

精彩评论

暂无评论...
验证码 换一张
取 消