jQuery Validate URL, adding “http://”

A project we have going on here at ibrow towers involves quite a bit of jQuery Validation. Whilst the Validation plugin is great with the default functions it offers, what makes it truly excellent is the fact that it is easily extendable.

For example, one thing that has been bugging me is to validate a URL the user must type in the initial http://. But why? Can the validation not just assume that if, for example, www.robsearles.com is typed in, that the user actually meant http://www.robsearles.com?

Well, after a quick read of the documentation and a hack around this little irritant is now gone. It’s all down to addMethod() which lets you add a custom validation method. Lets create one called complete_url().

jQuery.validator.addMethod("complete_url", function(val, elem) {
    // will contain our validation code
}, 'You must enter a valid URL');

A quick word about return values. If the method returns true, everything is considered OK. However, if false is returned then validation is assumed to have failed.

Our new method needs to do three things:

  1. If no url, don’t do anything
  2. Check that the user had entered http:// in their URL, if not, add it in for them.
  3. Check that the URL is now valid. For this I just used the source for the original url validation method.

Lets translate this into some code:

jQuery.validator.addMethod("complete_url", function(val, elem) {
    // if no url, don't do anything
    if (val.length == 0) { return true; }
 
    // if user has not entered http:// https:// or ftp:// assume they mean http://
    if(!/^(https?|ftp):///i.test(val)) {
        val = 'http://'+val; // set both the value
        $(elem).val(val); // also update the form element
    }
    // now check if valid url
    // http://docs.jquery.com/Plugins/Validation/Methods/url
    // contributed by Scott Gonzalez: http://projects.scottsplayground.com/iri/
    return /^(https?|ftp)://(((([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:)*@)?(((d|[1-9]d|1dd|2[0-4]d|25[0-5]).(d|[1-9]d|1dd|2[0-4]d|25[0-5]).(d|[1-9]d|1dd|2[0-4]d|25[0-5]).(d|[1-9]d|1dd|2[0-4]d|25[0-5]))|((([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])*([a-z]|d|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))).)+(([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])*([a-z]|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF]))).?)(:d*)?)(/((([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:|@)+(/(([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:|@)*)*)?)?(?((([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:|@)|[uE000-uF8FF]|/|?)*)?(#((([a-z]|d|-|.|_|~|[u00A0-uD7FFuF900-uFDCFuFDF0-uFFEF])|(%[da-f]{2})|[!$&'()*+,;=]|:|@)|/|?)*)?$/i.test(val);
});

Validating the form with this new method is very straight forward:

$("#form1").validate({
    rules: {
        url: "complete_url"
    }
});

Feel free to use/copy/modify as you see fit. If you do use it, why not let me know, or drop me a trackback?

Have fun

Other jQuery Specific Posts

  • http://nlvraghavendra.wordpress.com/ NLV

    I dont understand what you are doing here

    if(!/^(https?|ftp):///i.test(val)) {
    val = ‘http://’+val; // set both the value
    $(elem).val(val); // also update the form element
    }

    • http://twitter.com/djjeck djjeck

      il the url is non-empty, and it doesn’t start with http, it adds http to it

  • http://nlvraghavendra.wordpress.com/ NLV

    I dont understand what you are doing here

    if(!/^(https?|ftp):///i.test(val)) {
    val = 'http://'+val; // set both the value
    $(elem).val(val); // also update the form element
    }

  • http://twitter.com/djjeck djjeck

    il the url is non-empty, and it doesn't start with http, it adds http to it

  • Mosselman

    Thank you so much, prevented me from killing my monitor with my keyboard.

  • http://www.naukaplywania.org/ Kamil

    Small tune :>
    if(!/^(https?|ftp):///i.test(val)) {

    val = ‘http://’+val; // set both the value
    $(elem).val(val); // also update the form element
    }
    else
    {
    val = val.replace(/(http://)+/,’http://’);
    $(elem).val(val); // also update the form element
    }

    it fixes situation when user starts entering text while validation is on so when he/she writes htt..then your code will make http://htt so at the end we will have http://http://smth.com

    • yorlik

      I found that while your modification allowed it to eventually reduce the url to just one http://, it does not prevent the awkward behavior of throwing in an extra http://. It most likely would be very confusing to an end user.

      In addition, if you intend to add a url of https:// or ftp://, it leaves the additional http:// at the beginning. I realize you could deal with both the https and ftp in addition to the http://. However, see me next post and let me know what your thoughts are.

  • http://abouteverythingandnothing.info/ rymo

    I don't get your regexp, too complicated. I pasted it into expresso and as sample text url to this page…guess what :) url didn't pass :P

  • yorlik

    After adding this function, I found that I need to modify the following line:

    if(!/^(https?|ftp):///i.test(val)) {

    because

    //i.test(val))

    was being treated as a comment. The resulting change was to enclose the entire test in another set of parentheses as follows:

    if(!(/^(https?|ftp):///i.test(val))) {

    In addition, the entire method was awkward in its functionality if a user need to change the url first entered. By changing the code to the following, if the url is 7 characters or less (few url’s will be), it uses the standard url check and displays an error message without adding anything. However, once the url reaches 8 characters (the equivalent of https://), it will add http:// to the beginning if it is not http://, https://, or ftp://. Changed code follows:

    // if short url, don’t add anything
    if (val.length > 7) {
    // if user has not entered http:// https:// or ftp:// assume they mean http://
    if(!(/^(https?|ftp):///i.test(val))) {
    val = ‘http://’+val; // set both the value
    $(elem).val(val); // also update the form element
    }
    }
    // now check if valid url

    Please let me know what you think.

    • Yorlik

      just a note: you still need to check for a zero length otherwise it will generate an error even when not a required field. be sure to include the line:

      if (val.length==0) {return true;}

      before

      if(val.length > 7 {

  • yorlik

    I found that while your modification allowed it to eventually reduce the url to just one http://, it does not prevent the awkward behavior of throwing in an extra http://. It most likely would be very confusing to an end user.

    In addition, if you intend to add a url of https:// or ftp://, it leaves the additional http:// at the beginning. I realize you could deal with both the https and ftp in addition to the http://. However, see me next post and let me know what your thoughts are.

  • yorlik

    After adding this function, I found that I need to modify the following line:

    if(!/^(https?|ftp):///i.test(val)) {

    because

    //i.test(val))

    was being treated as a comment. The resulting change was to enclose the entire test in another set of parentheses as follows:

    if(!(/^(https?|ftp):///i.test(val))) {

    In addition, the entire method was awkward in its functionality if a user need to change the url first entered. By changing the code to the following, if the url is 7 characters or less (few url's will be), it uses the standard url check and displays an error message without adding anything. However, once the url reaches 8 characters (the equivalent of https://), it will add http:// to the beginning if it is not http://, https://, or ftp://. Changed code follows:

    // if short url, don't add anything
    if (val.length > 7) {
    // if user has not entered http:// https:// or ftp:// assume they mean http://
    if(!(/^(https?|ftp):///i.test(val))) {
    val = 'http://'+val; // set both the value
    $(elem).val(val); // also update the form element
    }
    }
    // now check if valid url

    Please let me know what you think.

  • Yorlik

    just a note: you still need to check for a zero length otherwise it will generate an error even when not a required field. be sure to include the line:

    if (val.length==0) {return true;}

    before

    if(val.length > 7 {

  • http://www.facebook.com/rkorebrits Richard Andrew Korebrits

    Very nice!

  • http://www.facebook.com/rkorebrits Richard Andrew Korebrits

    Very nice!