Tuesday, 13 December 2016

Extending jQuery Validation to cope with whitespace

I like formatting HTML; I go through all sorts of weird and wonderful ways of formatting HTML. One of my favourite things is to format forms so I can see things properly as I'm coding without too much horizontal scrolling, as such, I end up with forms a little like this:

<form 
  class="formTwo" 
  id="formTwo" 
  method="get" 
  action="">
    <fieldset>
        <legend>
            Test Two
        </legend>
        <p>
            <label 
              for="word2">
                Word 2 (required, at least 2 characters)
            </label>
            <input 
              id="word2" 
              name="word2" 
              type="text"/>
        </p>
        <p>
            <label 
              for="comment2">
                Comment 2 (required)
            </label>
            <textarea 
              id="comment2" 
              name="comment2">
              </textarea>
        </p>
        <p>
            <input 
              class="submit" 
              type="submit" 
              value="Submit"/>
        </p>
    </fieldset>
</form>

The thing is the Textarea ends up having a shed load of white space within it. This means that when I get around to validating that the Textarea has content using jQuery Validation I end up getting false positives as it counts whitespace as a valid input. All I'd need to do to pass the validation for the form above, with the following validation rules in place:

$("#formTwo").validate({
    "rules":{
        "word2": {
            "required": true,
            "minlength": 2
        },
        "comment2": "required"
    },
    "messages": {
        "word2": {
            "required": "Please enter a word",
            "minlength": "Your word must consist of at least 2 characters, with no spaces"
        },
        "comment2": "Don't be a prat!"
    }
});

Is to enter 2 spaces!

I've boon looking around at ways of solving this for a while, as it isn't only an issue for people who have odd indentation habits and I've come across two main ways of sorting it. One is to copy the required method, replace it and then call it again after running the replacement; the other is to extend it. I think that I prefer extending it but here are the two methods I've come across:

Copy, repalce and implement

$.validator.methods.oldRequired = $.validator.methods.required;
$.validator.addMethod("required", function(value, element, param) {
    if (value.trim().length === 0) {
        return false;
    }
    return $.validator.methods.oldRequired.call(this, value, element, param);
}, $.validator.messages.required);

Extend

$.extend($.validator.methods, {
    required: function(b, c, d) {
        if (!this.depend(d, c)) return "dependency-mismatch";
        if ("select" === c.nodeName.toLowerCase()) {
            var e = a(c).val();
            return e && e.length > 0
        }
        return this.checkable(c) ? this.getLength(b, c) > 0 : b.trim().length > 0
    }
});

Both methods add a check on the trimmed value passed to the method; ensuring that whitespace is removed before the value is tested.

I think I prefer the extension method, it was inspired by this answer, whereas the first method was stolen from Craig Stuntz.

It might be less robust, though, especially if the plugin undergoes a radical change and the required method alters a great deal, but I think that that's a small price to pay for elegance.