[英]Can I programmatically apply Angular validation directives inside a custom directive?
我发现html输入有以下几种模式,这适用于电话号码:
<input type="text" ng-model="CellPhoneNumber" required ng-pattern="/^[0-9]+$/" ng-minlength="10" />
我想创建一个自定义指令,无论何时应用,都会告诉Angular应用所有这三个规则,例如:
<input type="text" ng-model="CellPhoneNumber" bk-ng-validation="phoneNumber"/>
然后,我的指令中的代码将找到并调用一个名为phoneNumber
的函数,其中我希望看到类似于:
清单1:
function bkNgPhoneNumber(model) {
// This is purely SPECULATIVE pseudo-code, just to convey an idea.
model.errors.add(applyMinLength(10, model));
model.errors.add(applyMaxLength(15, model));
model.errors.add(applyPattern("/^[0-9]+$/", model));
}
我更喜欢上述方法而不是'为这些规则重写代码,例如:
清单2:
function phoneNumber(model) {
if (model.length < 10 || model.length > 15) {
model.errors.add("Must be 10 to 15 chars!");
}
}
我不想废除所有基于属性的指令,但最好创建一个'宏'指令,它将调用我的清单1代码,该代码将实习调用一组更“微观”的验证。
一种方法(即应用现有验证器而不再重复编写代码)将添加验证指令的相应属性并强制重新编译。 这将要求您的指令具有足够高的优先级,并且也是terminal: true
。
app.directive("bkNgValidation", function($compile){
return {
priority: 10000,
terminal: true,
link: function(scope, element){
element.attr("ng-required", "true");
element.attr("ng-minlength", 20);
element.attr("ng-maxlength", 30);
// prevent infinite loop
element.removeAttr("bk-ng-validation");
$compile(element)(scope);
}
};
});
如果您使用的是更多验证,则可以创建一个负责识别和验证元素的服务,而不受任何限制。 角度的默认指令保持不变。
例:
module.service('$Validation', ["$compile",function($compile){
this.validators = {
'phoneNumber': [['required', 1], ['minlength',6], ['maxlength', 10], ['pattern', /^[0-9]+$/.source]],
'phoneNumber2Custom': function(value){
return /^[0-9]{6,10}$/.test(value)
},
'userTwitter': function(value){
return /^@(.+)/.test(value)
}
// ...etc... /
}
this.add = function(scope, element, attrs, model){
var name = attrs.bkNgValidation, type;
if(!(type = this.validators[name])) return;
else if(angular.isFunction(type)) return (model.$validators[name] = type);
element.removeAttr("bk-ng-validation");
angular.forEach(type, function(expr){
element.attr(expr[0], expr[1])
});
$compile(element)(scope)
};
}]).directive('bkNgValidation', ["$Validation", function ($Validation) {
return {
require: '?ngModel',
priority: 1e5,
link: function(){
$Validation.add.apply($Validation, arguments);
}
}
}])
你可以尝试这种方法:
.directive('bkNgValidation', function () {
return: {
link: function (scope, element, attrs) {
if (attrs['bk-ng-validation'] === 'phoneNumber') {
element.$validateModel(function (value, validator) {
if (value.length < 10 || value.length > 15) {
validator.$setValidity('phone', true);
} else {
validator.$setValidity('phone', false);
}
});
}
}
}
})
您可以创建一个新组件,其中包括对所有必需验证器的控制。 您的组件看起来像:
<my-control name="field" ng-model="text"></my-control>
所有必需的逻辑组件都应保留在内部 为此,使用模板创建my-control
指令。 在模板内部,您可以输入带有验证属性的输入:
<input type="text" ng-model="value" class="form-control" ng-pattern="'^(?!ng-*)'" minlength="3">
然后,您需要将组件上的ng-model值绑定到输入:
angular.module('app', []).directive('myControl', function() {
return {
restrict: 'E',
require: 'ngModel', //import ngModel into linking function
templateUrl: 'myControl.tpl',
scope: {}, //our component can have private properties, isolate it
link: function(scope, elm, attrs, ngModel) {
// reflect model changes via js
ngModel.$render = function() {
scope.value = ngModel.$viewValue;
};
// update model value after changes in input
scope.$watch('value', function(value) {
ngModel.$setViewValue(value);
});
}
};
});
这是一个演示 ,您可以看到此组件的运行及其工作原理。
你正在以相反的方式前进,因为你假设指令是非常费力的维护,并希望保持一个给你所需的所有验证,具体取决于元素。
这是一个有趣的方法,但是你需要警告这种方法的模块性:将这么多的劳动分配给一个指令只是违背了做“纯粹的角度方式”来做事情的最佳实践。
如果你想继续这个想法,我建议你查看ngModelController
( AngularJS Docs )属性,这些属性可以注入一个指令的link()
函数。 更准确地说, $validators
。
您可以向所需的NgModel控制器添加多少$validators
。
在验证期间,您可以为返回布尔值的元素设置/取消设置有效性:
app.directive('validator', function () {
var definition = {
restrict: 'A',
require: '?ngModel',
link: function (scope, element, attrs, ngModel) {
// Return if no ngModelController
if (!ngModel) {
return;
}
ngModel.$validators.validateLength = function (modelValue, viewValue) {
// modelValue === the value of the ngModel, on the script side
// viewValue === the value of the ngModel, on the HTML (rendered) side
//
// you can set-up $parsers, $formatters, $validators, etc, to handle the element
return !(modelValue.length > 20);
}
}
};
return definition;
});
我建议你阅读更多关于这个实现的内容,因为某些操作可以在操纵元素上的角度上中断$digest
循环的流量。
就像我在评论中提到的那样,这是一个带有工作示例的Plunkr 。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.