我已经创建了一些指令,可以帮助我检查看起来或多或少像这样的表单中的输入有效性:
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);
}
}
}
});
现在,我想将自定义消息添加到输入,选择等等但未通过验证但是我不想一个接一个地添加一个span或somethinng与ng-if(thata)我想避免的很多工作。)
我的第一次尝试是创建一个这样的指令:
app.directive("ngInvalid", function(){
restrict:"C",
...
});
但那不起作用所以现在我正在尝试这个
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;
}
}
}
...
我一直在查看文档并浏览一些问题,但大多数情况下我找到了需要使用表单控制器的解决方案,我想避免这种情况。
是否有一些方法可以让我从输入中检索错误?
修改
为了说清楚,让我们说输入不是包装在表单标签内,而是包含div或其他东西。我如何访问输入指令中的每个错误?
答案 0 :(得分:1)
我发布的上一个方法存在一些问题。对类的监视没有按预期工作,当类实际更改时,它没有被触发,但是当输入下一个输入字符时。例如,当在空白之后,您在输入中引入了一个新字符,并且控制台中的日志和检查器中的类是不同的(可能是一个有角度的错误?)时,出现了所需的错误。
无论如何,我发现了我认为更好的解决方案:哦,当控件没有包含在表单标签内时,实际上可以访问有效性检查
那是代码(我还没有添加模糊检查,但应该很容易)
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);
我想指出一些事情:
第一:我可以使用ctrl来访问指令内每个控件的所有错误。$ error(为了上帝的缘故,为什么在所有堆栈溢出中没有单一的答案说你可以使用。$ 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!!!
在这里你可以看到它有效:
答案 1 :(得分:0)
简答
不,没有表格控制器就无法进行有效性检查。
解决方法强>
我使用输入指令来实现我想要的,但它对我来说似乎不太优雅(我真的想使用影响textareas的指令并选择而不必将my-custom-directive添加到每个字段我想验证)
(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>");
}
}
}
}
});
})();
以下是工作码本的链接:http://codepen.io/sergio0983/pen/AXxNpN?editors=1111
出于某种原因,在codepen中,如果我没有在angular元素上使用$ selector,那么错误就不会被删除