2016-07-15 67 views
0

我已经创造了一些指令,它们帮我检查输入的有效性,看起来或多或少像这样的形式检索输入验证错误:从内部指令

app.directive("initialDate", function(){ 
    return{ 
     require: '?ngModel', 
     restrict:"A", 
     link:function(scope, element, attrs, ngModel){ 
      scope.$watch(attrs.ngModel, function() { 
       validate(); 
      }); 
      attrs.$observe('initialDate', function() { 
       validate(); 
      }); 
      var validate = function() { 
       var date = Date.parse(ngModel.$viewValue); 
       var initialDate = Date.parse(attrs.initialDate); 
       ngModel.$setValidity('initial-date', date >= initialDate); 
      } 
     } 
    } 
}); 

现在,我想自定义消息添加到输入,选择等等,这些都没有通过验证,但我不想一个接一个地用ng-if添加一个span或somethinng(这是我想避免的很多工作)。

我第一次尝试是创建这样的指令:所以现在

app.directive("ngInvalid", function(){ 
    restrict:"C", 
    ... 
}); 

但是didn't工作我正尝试这一

app.directive("input", function(){ 
    return { 
     require:"?ngModel", 
     link:function(scope, element, attrs, ctrl){ 
      scope.$watch(function() { 
       return element.attr('class'); 
      }, function(newVal, oldVal){ 
       if (newVal == oldVal) return;  
       if (element.hasClass("ng-invalid")){ 
        element.parent().append("<span class = 'error' style='color:red'>There was an error</span>"); 
       }else{ 
        element.parent().find(".error").remove(); 
       } 
      }); 
     } 
    } 
}); 

所以,这一个工程(更或更少,它需要更多的工作,嘿嘿),但我将不得不创建一个选择,textareas等,并对每种类型的错误进行一些检查,如果我想显示自定义消息。

此外,它真的看起来很脏。我真的觉得一定有什么事情,我可以说看起来更像这个指令内做到:

... 
link:function(scope, element, attrs, ctrl){ /***element is the input or select or textarea... ***/ 
    if (!element.$isValid){ 
     switch (element.$validationErrors[0]){ 
      case "emailValidation": element.parent().append("<span class = 'error' style='color:red'>Email format not correct</span>"); break; 
      case "initialDate": element.parent().append("<span class = 'error' style='color:red'>Date cannot be previous to {{initialDate}}</span>"); break; 
      case "pattern": element.parent().append("<span class = 'error' style='color:red'>Format incorrect</span>"); break; 
     } 

    } 
} 
... 

我一直在寻找在文档和浏览的一些问题,但主要是我发现需要使用的解决方案表单控制器,我想避免这种情况。

是否有一些方法可以让我从输入中检索错误?

编辑

要清楚,let's说,输入没有包装形式的标签里面,但股利,或别的东西。我如何访问输入指令中的每个错误?

+2

看一下ng-messages – dewd

+0

看起来不错,但并不能解决我想要实现的两件事:如果我想在每个字段上显示一个显示错误,则不依赖于使用表单并必须为每个输入创建一个组件。 – sergio0983

回答

0

简答

不,it's无法访问有效性检查,而不表单控件。

解决方法

我使用的输入指令来实现我想要的东西,但它doesn't似乎太高雅了,我(我倒是很喜欢使用文本域影响而不必选择指令我-定制指令添加到每个领域我想验证)

(function(){ 
    var lang = navigator.language.substr(0,2) || navigator.userLanguage.substr(0,2); 

    const E_UNKNOWN = 0, 
    E_REQUIRED = 1, 
    E_NAN = 2, 
    E_MIN = 3, 
    E_MAX = 4, 
    E_EMAIL = 5, 
    E_MINLEN = 6, 
    E_MAXLEN = 7, 
    E_PATTERN = 8, 
    E_BLACKLIST = 9, 
    E_EQUAL = 10; 
    E_INITIALDATE = 11; 

    const ERR_MESSAGES = [ 
     {'es':'Error desconocido', 'en':'Unknown Error'}, 
     {'es':'Este campo es obligatorio', 'en':'This field is mandatory'}, 
     {'es':'Este campo debe ser numérico', 'en':'This field should be numeric'}, 
     {'es':'El valor es inferior al mínimo', 'en':'Value is lower than the minimum'}, 
     {'es':'El valor es superior al máximo', 'en':'Value is higher than the maximum'}, 
     {'es':'El formato de email no es válido', 'en':'Email format incorrect'}, 
     {'es':'No cumple longitud mínima', 'en':'Minimum length not matched'}, 
     {'es':'No cumple longitud máxima', 'en':'Maximum length not matched'}, 
     {'es':'El formato no es válido', 'en':'Format incorrect'}, 
     {'es':'Este valor no está permitido', 'en':'This value is not allowed'}, 
     {'es':'Los campos no coinciden', 'en':'Fields doesn´t match'}, 
     {'es':'La fecha es anterior a la fecha inicial', 'en':'This date is previous to the initial date'}, 
    ]; 

    var lang = navigator.language.substr(0,2) || navigator.userLanguage.substr(0,2); 

    app.directive("input", function(){ 
     return { 
      scope:{}, 
      link:function(scope, element, attrs, ctrl, ngModel){ 
       scope.blurred = false; 
       element[0].addEventListener("blur", function(){ 
        scope.blurred = true; 
        element.parent().find(".error").remove(); 
        checkValidity(); 
       }); 

       var checkValidity = function(){ 
        var classList = element.attr('class'); 
        if (!classList) return; 
        var matches = classList.match(/ng-invalid-(.*?)(\s|$)/); 
        if (matches == null) return; 
        if (!(1 in matches)) return; 

        var $err = matches[1]; 
        var $errMessage = ""; 

        switch($err){ 
         case "required": $errMessage = ERR_MESSAGES[E_REQUIRED][lang]; break; 
         case "number": $errMessage = ERR_MESSAGES[E_NAN][lang]; break; 
         case "min": $errMessage = ERR_MESSAGES[E_MIN][lang]; break; 
         case "max": $errMessage = ERR_MESSAGES[E_MAX][lang]; break; 
         case "email": $errMessage = ERR_MESSAGES[E_EMAIL][lang]; break; 
         case "minlength": $errMessage = ERR_MESSAGES[E_MINLEN][lang]; break; 
         case "maxlength": $errMessage = ERR_MESSAGES[E_MAXLEN][lang]; break; 
         case "pattern": $errMessage = ERR_MESSAGES[E_PATTERN][lang]; break; 
         case "blacklist": $errMessage = ERR_MESSAGES[E_BLACKLIST][lang]; break; 
         case "equals": $errMessage = ERR_MESSAGES[E_EQUAL][lang]; break; 
         case "initial-date": $errMessage = ERR_MESSAGES[E_INITIALDATE][lang]; break; 
         default: $errMessage = ERR_MESSAGES[E_UNKNOWN][lang]; break; 
        } 

        if (element.hasClass("ng-invalid")){ 
         element.parent().append("<span class = 'error'>"+$errMessage+"</span>"); 
        } 
       } 
      } 
     } 
    }); 
})(); 

这里是一个链接到一个工作codepen:http://codepen.io/sergio0983/pen/AXxNpN?editors=1111

出于某种原因,在codepen中,如果我不在角元素上使用$选择器,错误不会被删除()

0

我发布的上一个方法有一些问题。对班级的监视并不像预期的那样工作,当班级实际发生变化时并没有被解雇,而是当下一个输入字符被输入时。例如,所需的错误是在空白后在输入中引入了一个新的字符,并且控制台中的日志和检查器中的类是不同的(可能是有角度的错误)。

反正,我已经找到我认为是更好的解决方案:哦,it's实际上可以访问有效性检查时的控制是不是一个形式的标签

That's里面包裹代码(我didn't添加一个模糊账了,但应该很容易)

var errMsgDirective = function(){ 
    return{ 
     restrict:"E", 
     require:"?ngModel", 
     link:function(scope, element, attrs, ctrl, ngModel){ 
      if (!attrs.ngModel) return; 

      var lang = navigator.language.substr(0,2) || navigator.userLanguage.substr(0,2); 
      const E_UNKNOWN = 0, E_REQUIRED = 1, E_NAN = 2, E_MIN = 3, E_MAX = 4, E_EMAIL = 5, E_MINLEN = 6, E_MAXLEN = 7, E_PATTERN = 8, E_BLACKLIST = 9, E_EQUAL = 10; E_INITIALDATE = 11;  
      const ERR_MESSAGES = [ 
       {'es':'Error desconocido', 'en':'Unknown Error'}, 
       {'es':'Este campo es obligatorio', 'en':'This field is mandatory'}, 
       {'es':'Este campo debe ser numérico', 'en':'This field should be numeric'}, 
       {'es':'El valor es inferior al mínimo', 'en':'Value is lower than the minimum'}, 
       {'es':'El valor es superior al máximo', 'en':'Value is higher than the maximum'}, 
       {'es':'El formato de email no es válido', 'en':'Email format incorrect'}, 
       {'es':'No cumple longitud mínima', 'en':'Minimum length not matched'}, 
       {'es':'No cumple longitud máxima', 'en':'Maximum length not matched'}, 
       {'es':'El formato no es válido', 'en':'Format incorrect'}, 
       {'es':'Este valor no está permitido', 'en':'This value is not allowed'}, 
       {'es':'Los campos no coinciden', 'en':'Fields doesn´t match'}, 
       {'es':'La fecha es anterior a la fecha inicial', 'en':'This date is previous to the initial date'}, 
      ]; 
      var checkValidity = function(){ 
       if (!ctrl.$touched) return; 


       var errors = []; 
       for (var i in ctrl.$error){ 
        if (ctrl.$error[i] == false) continue;   
        switch (i){ 
         case "required": errors.push(ERR_MESSAGES[E_REQUIRED][lang]); break; 
         case "number": errors.push(ERR_MESSAGES[E_NAN][lang]); break; 
         case "min": errors.push(ERR_MESSAGES[E_MIN][lang]); break; 
         case "max": errors.push(ERR_MESSAGES[E_MAX][lang]); break; 
         case "email": errors.push(ERR_MESSAGES[E_EMAIL][lang]); break; 
         case "minlength": errors.push(ERR_MESSAGES[E_MINLEN][lang]); break; 
         case "maxlength": errors.push(ERR_MESSAGES[E_MAXLEN][lang]); break; 
         case "pattern": errors.push(ERR_MESSAGES[E_PATTERN][lang]); break; 
         case "blacklist": errors.push(ERR_MESSAGES[E_BLACKLIST][lang]); break; 
         case "equals": errors.push(ERR_MESSAGES[E_EQUAL][lang]); break; 
         case "initial-date": errors.push(ERR_MESSAGES[E_INITIALDATE][lang]); break; 
         default: errors.push(ERR_MESSAGES[E_UNKNOWN][lang]); break; 
        } 
       } 

       element.parent().find(".error").remove(); 
       if (errors.length == 0){ 

       }else{ 
        $errMessage = errors.join("; "); 
        element.parent().append("<span class = 'error'>"+$errMessage+"</span>"); 
       } 
      } 

      scope.$watch(function(){ 
       return JSON.stringify(ctrl.$error); 
      }, function(){ 
       checkValidity(); 
      }); 

      scope.$watch(function(){ 
       return ctrl.$touched; 
      }, function(){ 
       checkValidity(); 
      }) 
     } 
    } 
} 

app.directive("input", errMsgDirective); 
app.directive("textarea", errMsgDirective); 
app.directive("select", errMsgDirective); 

有一些事情我想指出:

1:我可以访问相对于里面的每个控制所有错误指令与ctr l。$错误(为了上帝的缘故,为什么在所有堆栈溢出中没有一个单一的答案,说你可以用。$ error?来访问控制错误。 ¬¬)

第二:我有一个真正的困难时期将是工作的手表:我尝试了所有的以下内容:

scope.$watch(attrs.ngModel, function(){...}) //This one did not work because the model doesn´t change when the validity checks are not met 
scope.$watch(ctrl.$valid, function(){...}) //Never fired 
scope.$watch(ctrl.$invalid, function(){...}) //Never fired 
scope.$watch(ctrl.$error, function(){...}) //Never fired 
scope.$watch(function(){ return ctrl.$error }, function(){...}) //Never fired 
scope.$watch(function(){ return JSON.stringify(ctrl.$error) }, function(){...}) //BINGO!!! 

在这里你可以看到它的工作:

http://codepen.io/sergio0983/pen/ZOvPvW?editors=1011