$parsers \ $formatters functions are not firing when the browser fills the form field automatically

Viewed 167

I have a certain custom validation directive in my application(code attached below). The problem is that when one or more of the form fields are required, and chrome fills them automatically, the fields remain invalid until the user changes them manually. I suspect that this happens due to the fact that chrome fills the fields before angular even bootstraps.

Is there a way to fix this?.

Code:

app.directive('myValidate', function($timeout, $filter) {
    return {
        require: 'ngModel',
        link: function(scope, elm, attrs, ctrl) {
              var validator = function(viewValue){
                var viewValueStr = viewValue + '';
                scope.valid = true;
                scope.fieldName = attrs.name;
                var nameStr = attrs.name + '';
                if(!attrs.displayName || attrs.displayName.length == 0){
                  // var nameObj = nameStr.split('_');
                  // for(var i = 0; i < nameObj.length; ++i){
                  //   nameObj[i] = nameObj[i].substr(0, 1).toUpperCase() + nameObj[i].slice(1);
                  // }
                  // var nameStrParsed = nameObj.join(' ');//olde code, working on name, not Hebrew comaptible
                  var nameStrParsed = attrs.placeholder + '';
                }
                else{//data-display-name attribute, the error display is different than the placeholder value
                  var nameStrParsed = attrs.displayName;
                }

                scope.fieldErrorDisplay = Boolean(nameStrParsed) ? nameStrParsed : $filter('translate')('THISFIELD');
                var valueRequired = scope.$eval(attrs.valueRequired);
                if(valueRequired && viewValueStr.length == 0 && !attrs.minLength){
                    scope.valid = false;  
                    scope.requirementSpec[nameStr] = [{
                      'msg' : scope.fieldErrorDisplay + ' ' + $filter('translate')('ISREQUIRED'),
                      'class' : undefined
                    }];
                  }
                  else{
                        // scope.fieldErrorDisplayObj[nameStr] = scope.fieldErrorDisplay + ' must meet the following requirements: ';
                        scope.requirementSpec[nameStr] = [];
                        if(attrs.minLength){
                          var itemValidity = viewValue.length >= attrs.minLength;
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' : $filter('translate')('MINLENGTH', {PARAM: attrs.minLength + ''}),
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        else if(attrs.valueRequired){
                          var itemValidity = viewValue &&  viewValueStr && viewValueStr.length >= 1;
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' : $filter('translate')('FIELDREQUIRED'),
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        if(attrs.maxLength){
                          var itemValidity = viewValue.length <= attrs.maxLength;
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' :  $filter('translate')('MAXLENGTH', {PARAM: attrs.maxLength + ''}),
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        if(attrs.minLetters){
                          var itemValidity = (viewValue && /[A-z]/.test(viewValue));
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' :  $filter('translate')('MINLETTERS', {PARAM: attrs.minLetters + ''}),
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        if(attrs.minNumbers){
                          var itemValidity = (viewValue && /\d/.test(viewValue));
                          scope.valid = !itemValidity ? false : scope.valid;
                          var item = {
                            'msg' : $filter('translate')('MINNUMBERS', {PARAM: attrs.minNumbers + ''}),
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);
                        }
                        if(attrs.validUrl){
                          // if(viewValue.indexOf('http') == -1){
                          //   viewValue = 'http://' + viewValue;
                          //   ctrl.$setViewValue(viewValue);
                          // }
                          // else if(viewValue.indexOf('http') != 0){
                          //   var httpIndex = viewValue.indexOf('http');w
                          //   viewValue = viewValue.substr(httpIndex);
                          //   ctrl.$setViewValue(viewValue);
                          // }
                          // var urlPattern = new RegExp("(http|https)://[\w-]+(\.[\w-]+)+([\w.,@?^=%&amp;:/~+#-]*[\w@?^=%&amp;/~+#-])?");
                           var urlPattern = new RegExp(/^(https?):\/\/(((([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);
                           //(http|https):\/\/([a-zA-Z0-9]+\.)?[a-zA-Z0-9][a-zA-Z0-9-]+\.[a-zA-Z]{2,6}?(.+){0, 100}$/i)
                          var itemValidity = !viewValue || viewValue.length == 0 || urlPattern.test(viewValue);
                          scope.valid = !itemValidity ? false : scope.valid;
                          // console.log(itemValidity);
                          var item = {
                            'msg' : $filter('translate')('VALIDURL'),
                            'class' : itemValidity ? 'valid' : undefined
                          };
                          scope.requirementSpec[nameStr].push(item);

                        }
                  }

                  if(scope.valid) {
                      ctrl.$setValidity(nameStr, true);
                      elm.removeClass('ng-required-invalid').removeClass('validatorError').removeClass('ng-invalid').addClass('ng-valid');
                      return viewValue;
                  } 
                  else {
                      ctrl.$setValidity(nameStr, false);                    
                      return undefined;
                  }
              }
              if(!scope.requirementSpec){
                scope.requirementSpec = {};
              }
              if(Boolean(attrs.valueRequired) || Boolean(attrs.minLength)){
                  ctrl.$setValidity(attrs.name, false);
                  // elm.removeClass('ng-valid').addClass('ng-invalid');
              }

            ctrl.$parsers.unshift(function(viewValue) {
              return validator(viewValue);
            });
            ctrl.$formatters.unshift(function(viewValue) {
              if(viewValue && viewValue != "" && viewValue.length > 0)
                return validator(viewValue);
            });
        }
    };
})
2 Answers
Related