Rewriting AngularJS URL Validator

AngularJS accepts this for a valid URL:

var URL_REGEXP = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/; 

Django accepts this:

 regex = re.compile( r'^(?:http|ftp)s?://' # http:// or https:// r'(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[AZ]{2,6}\.?|[A-Z0-9-]{2,}\.?)|' #domain... r'localhost|' #localhost... r'\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})' # ...or ip r'(?::\d+)?' # optional port r'(?:/?|[/?]\S+)$', re.IGNORECASE) 

The main practical difference is that AngularJS accepts http://some-host-without-tld , while Django allows http://localhost as a valid URL without TLD.

Since the problem is to rewrite the Django URL checker, I want to rewrite the AngularJS checker. I tried so that works:

 app.overwriteUrlValidator = function(ngModel) { // Django RegExp, ported to JS. var URL_REGEXP = /^(?:http|ftp)s?:\/\/(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[AZ]{2,6}\.?|[A-Z0-9-]{2,}\.?)|localhost|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d+)?(?:\/?|[\/?]\S+)$/gi; // Same validator as AngularJS's, only with a different RegExp. function urlValidator(value) { if (ngModel.$isEmpty(value) || URL_REGEXP.test(value)) { ngModel.$setValidity('url', true); return value; } else { ngModel.$setValidity('url', false); return undefined; } } // This is the part I'm not happy about. I need to use a timeout // because my code is executed before Angular adds its URL validator. // If I add mine before Angular does, it will not work for ??? reason. window.setTimeout(function() { ngModel.$formatters.push(urlValidator); ngModel.$parsers.push(urlValidator); }, 100); }; /** * Keep track of user interaction with input fields */ app.inputDirective = function() { function link(scope, element, attrs, ngModel) { if (ngModel && attrs.type === 'url') { app.overwriteUrlValidator(ngModel); } } return { restrict: 'A', require : '?ngModel', link : link }; }; app.directive('input', app.inputDirective); app.directive('textarea', app.inputDirective); 

I would rather not switch to another validation directive because I will have to update and verify a lot of code.

Does anyone know a lasting way to do this?

+6
source share
3 answers

As with Angular 1.3, it is now quite easy now to completely overwrite the existing $validators :

 myApp.directive('input', function() { function link(scope, element, attrs, ngModel) { function allowSchemelessUrls() { // Match Django URL validator, which allows schemeless urls. var URL_REGEXP = /^((?:http|ftp)s?:\/\/)(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[AZ]{2,6}\.?|[A-Z0-9-]{2,}\.?)|localhost|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d+)?(?:\/?|[\/?]\S+)$/i; // Silently prefixes schemeless URLs with 'http://' when // converting a view value to model value. ngModel.$parsers.unshift(function(value) { if (!URL_REGEXP.test(value) && URL_REGEXP.test('http://' + value)) { return 'http://' + value; } else { return value; } }); ngModel.$validators.url = function(value) { return ngModel.$isEmpty(value) || URL_REGEXP.test(value); }; } if (ngModel && attrs.type === 'url') { allowSchemelessUrls(); } } return { require: '?ngModel', link: link }; }); 
+6
source

You can use the ng-pattern attribute to reinforce the pattern used for validation. (I have not seen a way to weaken the model used - perhaps this is good.)

+1
source

We can create a URL verification directive. This example also adds a GUI validation response. Added Bootstrap validation class.

 app.directive('validateWebAddress', function () { var URL_REGEXP = /^((?:http|ftp)s?:\/\/)(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+(?:[AZ]{2,6}\.?|[A-Z0-9-]{2,}\.?)|localhost|\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})(?::\d+)?(?:\/?|[\/?]\S+)$/i; return { require: 'ngModel', restrict: 'A', link: function (scope, element, attrs, ctrl) { element.on("keyup", function () { var isValidUrl = URL_REGEXP.test(element.val()); if (isValidUrl && element.hasClass('alert-danger') || element.val() == '') { element.removeClass('alert-danger'); } else if (isValidUrl == false && !element.hasClass('alert-danger')) { element.addClass('alert-danger'); } }); } } }); 

Use this in your tag. Model required. Therefore, be sure to identify the model.

 <input type="url" validate-web-address ng-model="DummyClass.WebAddress" class="form-control" id="webaddress" placeholder="Web Address" /> 
0
source

All Articles