9

I have a need for users to be able to create partial URLs without needing to type the full URL each time.

For example, say I plan on the url being www.example.com/areas/{userinput}/home. I want the user to be able to enter some text in a text box and I want to validate that it is a valid URL.

The URL validator functions like this:

url: function(value, element) {
        return this.optional(element) || /giantregex/.test(value);
}

I've attempted adding a validation method to the validator via the following:

$.validator.addMethod("exturl", function(value) {
    return $.validator.methods.url.call($.validator, "http://www.example.com/areas/" + value + "/home");
});

However, when the form is validated and my extension is called, I keep getting this error:

Uncaught TypeError: Object function (d,a){this.settings=b.extend(true,{},b.validator.defaults,d);this.currentForm=a;this.init()} has no method 'optional' 

optional looks to be a method on the $.validator object but I can't figure out how to call the validator url method.

scottm
  • 27,829
  • 22
  • 107
  • 159

2 Answers2

17

jQuery Validation Plugin - v1.11.0

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-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:)*@)?(((\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5])\.(\d|[1-9]\d|1\d\d|2[0-4]\d|25[0-5]))|((([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])))\.?)(:\d*)?)(\/((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)+(\/(([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)*)*)?)?(\?((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|[\uE000-\uF8FF]|\/|\?)*)?(\#((([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(%[\da-f]{2})|[!\$&'\(\)\*\+,;=]|:|@)|\/|\?)*)?$/i.test(val);
});

Then:

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

From http://www.robsearles.com/2010/05/jquery-validate-url-adding-http/

Barno
  • 3,271
  • 5
  • 28
  • 58
  • if(!/^(https?|ftp):\/\//i.test(val)) { This line is commented out as because of // – Sam Nov 09 '13 at 06:10
  • Your code is missing `this.optional(element)`... pretty important stuff. Without it, you cannot leave this field blank, even when you want the field to be optional! – Sparky Jun 23 '17 at 16:22
2

I managed to make it work without errors, here is the JS code I used:

$(document).ready(function(){

    function validateURL(value){
      // URL validation from http://stackoverflow.com/questions/3809401/what-is-a-good-regular-expression-to-match-a-url
      var expression = /[-a-zA-Z0-9@:%_\+.~#?&//=]{2,256}\.[a-z]{2,4}\b(\/[-a-zA-Z0-9@:%_\+.~#?&//=]*)?/gi;
      var regex = new RegExp(expression);
      return value.match(regex);
    }

    $.validator.addMethod("urlvalidation", function(value, element) {
      return this.optional(element) || validateURL(value);
    }, "URL is not valid");

    $('#frm_validation').validate({
      rules : {
          urlvalidation : { urlvalidation : true }
      }
    });  

});​

You can see it in action on this JSFiddle.

Olivier Payen
  • 15,198
  • 7
  • 41
  • 70
  • This still requires that I copy the regex. It has to be possible to create my url from user input before validating that it's a valid URL and then calling the internal URL validate method to validate my formatted string. – scottm Oct 30 '12 at 16:26
  • 1
    Ok, I didn't understand that the requirement was to avoid copying the regex. In that case, why don't you call your URL validation function like so `return this.optional(element) || urlValidationFunction(value)`? – Olivier Payen Oct 30 '12 at 16:30
  • That's exactly what I did and outlined in the question. I ended up with the errors also in the question. – scottm Oct 30 '12 at 17:20
  • I edited my answer, tell me if it satisfies your requirements. – Olivier Payen Oct 31 '12 at 08:37