59

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 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?

Sparky
  • 98,165
  • 25
  • 199
  • 285
Tom
  • 14,041
  • 16
  • 64
  • 80
  • 2
    Great question. Jörn said he would fix this as part of the plugin itself. But that was about a year ago. I can confirm that white space at the end of a field does make it invalid for me. I'm using version 1.5.5. (Jorn's post: http://www.mail-archive.com/jquery-en@googlegroups.com/msg55651.html) – Nathan Long Dec 01 '09 at 17:15

16 Answers16

95

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
}
Mario Menger
  • 5,862
  • 2
  • 28
  • 31
MDP
  • 982
  • 7
  • 2
  • 1
    The beauty of this approach is that the server side receives clean (trimmed) values too. But it would be quite an effort to add this if you have many validated forms with similar requirements. This is why I've combined this with @hwiechers' answer below :) – Halil Özgür Mar 27 '12 at 16:20
  • 1
    ... A warning could be useful where this is used: "Leading and trailing spaces are not valid and trimmed." Especially for users who want to use a password with leading/trailing spaces. They would be unable to log in since the recorded passwords would be different from the ones they'd intended. – Halil Özgür Mar 27 '12 at 16:26
  • 12
    A warning for an issue which I've detected after using this for quite some time: if the form is submitted while the the field is invalid, entering legitimate space (e.g. the ones between names and surnames) afterwards into it gets hard esp. for slower typers: http://jsfiddle.net/halilim/ftwqg Set `onkeyup: false` to prevent this. – Halil Özgür Mar 28 '13 at 21:03
  • @HalilÖzgür where do I have to put "onkeyup: false" to prevent that issue? Thank you! – superpuccio Feb 10 '14 at 09:07
  • 1
    @superpuccio for all of your validations: `jQuery.validator.setDefaults({ onkeyup: false /* , other defaults */ });` for a single instance: `.validate({ onkeyup: false, rules: { /* ... */ } });` – Halil Özgür Feb 10 '14 at 09:29
  • While this would work fine for a single field, it's not very scalable. If I want to apply it to all fields at once I'd prefer not to have to remember to add this to the options and maintain it for every field in every form I use the validator with. Also, it's difficult if you want to use class or data attributes to specify the rules, rather than the options object. Is there a way to apply it more generally w/o modifying the library itself? – jinglesthula Jan 23 '15 at 23:47
  • This requires 2 dom operations which is far away from a nice solution. Atm we discuss a native feature to solve the problem, see my answer below – staabm Oct 21 '15 at 17:15
  • This was a huge help. Thank you! – accord_guy May 10 '17 at 08:14
  • It may be worth mentioning that the word 'Email' at the start is case sensitive. So if your field is named 'email', you should write the first word as 'email' – accord_guy May 10 '17 at 08:15
24

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.

james_bond
  • 6,778
  • 3
  • 28
  • 34
hwiechers
  • 14,583
  • 8
  • 53
  • 62
  • 3
    Very useful since all methods in all forms can be modified once. To combine this with the above (accepted) answer, replace `arguments[0] = $.trim(arguments[0]);` with `var el = $(arguments[1]); el.val($.trim(el.val()));` (two lines). – Halil Özgür Mar 27 '12 at 16:21
  • 1
    A note after using this for quite a time: see [my warning comment](http://stackoverflow.com/questions/1827483/jquery-validate-plugin-how-to-trim-values-before-form-validation/6472021#comment22281032_6472021) under [the accepted answer](http://stackoverflow.com/a/6472021/372654), which is especially true when you apply trimming to all fields. – Halil Özgür Mar 28 '13 at 21:04
  • This was incredibly helpful in my validations today. Can't tell you how much this helped me, but I'm very glad it was there in the webz for me to see. Thanks! – PKD Feb 10 '15 at 22:37
  • I don't understand where should I be putting this code? – user4584963 Dec 11 '15 at 16:28
  • 1
    It doesn't work on signup form with password & confirm_password – Duc Bui Apr 11 '16 at 06:50
  • What's the point of validating if you'll still allow a user to submit invalid input? – Supreme Dolphin Aug 20 '18 at 15:35
15

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.

tmorell
  • 549
  • 5
  • 14
  • This is the right solution for me since I'm using `$.validator.setDefaults({...})` to set defaults for all my forms, so I don't have to add custom code everywhere. – Luciano Fantuzzi Jul 09 '19 at 15:27
15

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)
 });
Community
  • 1
  • 1
mark
  • 59,016
  • 79
  • 296
  • 580
  • 1
    The best solution here; it's even better if you make it the default: https://gist.github.com/mnbayazit/b4595fafcbee4f3a7c25 – mpen Dec 05 '14 at 18:12
7

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
  }
}
jeremyzilar
  • 197
  • 1
  • 3
  • 8
  • 6
    I'm looking at the implementation and it doesn't appear to strip anything. It simply disallows any whitespace (including between letters). – mpen Dec 05 '14 at 18:04
5

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.

Tom
  • 14,041
  • 16
  • 64
  • 80
5

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');
Tim Hutchison
  • 3,483
  • 9
  • 40
  • 76
sevencardz
  • 1,539
  • 1
  • 10
  • 3
5

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;
            }
        }
    }
});
Craig Wohlfeil
  • 627
  • 9
  • 9
3

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.");
RyanCodes
  • 175
  • 1
  • 5
3

This is what works for me:

$(':input').change(function() {
    $(this).val($(this).val().trim());
});
  • Please explain instead of just posting a block of code. – eddie_cat Jul 11 '14 at 21:05
  • This does not allow space between words. – philippinedev Sep 10 '16 at 06:12
  • This code block appears to trim value of `:input` element every time it changes. It will not allow you to type spaces as a character, since `change` event fires any time user try to change input value. Meaning that if you try to type `this is a red wolf`, actual input will be `thisisaredwolf`. As per validation, this behavior might be largely unacceptable. – HelpNeeder Jun 07 '19 at 02:56
2

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

$("#cemail").blur(function(){
  $(this).val(jQuery.trim($(this).val());
});
Psytronic
  • 6,043
  • 5
  • 37
  • 56
  • Thanks for the suggestion - I tried it out but unfortunately, the order that the events trigger is random and often the validation is done before the trimming - so the user gets a error and also has their input corrected so probably gets even more confused. – Tom Dec 01 '09 at 22:11
  • 1
    What about changing it to .change()? When does the validation get triggered then? Isn't it usually on form submit? – Psytronic Dec 02 '09 at 09:01
  • I think it would. I tried adding $('#cemail').bind('change',function (e) { $(this).val($.trim($(this).val()));}); AFTER the jQuery library but BEFORE the validation plugin seems to work – robnardo Jan 30 '14 at 20:22
2

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>
adiga
  • 34,372
  • 9
  • 61
  • 83
Savoo
  • 933
  • 7
  • 14
1

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())
lededje
  • 1,859
  • 1
  • 16
  • 25
  • This code block appears to trim value of `:input` element every time it changes. It will not allow you to type spaces as a character, since `change` event fires any time user try to change input value. Meaning that if you try to type `this is a red wolf`, actual input will be `thisisaredwolf`. As per validation, this behavior might be largely unacceptable. – HelpNeeder Jun 07 '19 at 02:57
1

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

Amul
  • 149
  • 1
  • 3
0

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.

mpen
  • 272,448
  • 266
  • 850
  • 1,236
-1

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()));
});
Adrian P.
  • 5,060
  • 2
  • 46
  • 47