我发现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代码,该代码将实习调用一组更“微观”的验证。
答案 0 :(得分:19)
实现此目的的一种方法(即应用现有验证器而不再重复编写代码)将添加验证指令的相应属性并强制重新编译。这将要求您的指令具有足够高的优先级,并且也是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);
}
};
});
<强> Demo 强>
答案 1 :(得分:6)
如果您使用的是更多验证,则可以创建一个负责识别和验证元素的服务,而不受任何限制。角度的默认指令仍然存在。
示例:
Context ctx = Context.enter();
ctx.getWrapFactory().setJavaPrimitiveWrap(false);
<强> Demo 强>
答案 2 :(得分:3)
您可以尝试这种方法:
.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);
}
});
}
}
}
})
答案 3 :(得分:1)
您可以创建一个新组件,其中包括所有必需验证器的控制。您的组件看起来像:
<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);
});
}
};
});
以下是demo,您可以看到此组件的运行及其运作方式。
答案 4 :(得分:1)
你正在以相反的方式进行,因为你假设指令是非常费力的维护,并希望保留一个指令以提供所需的所有验证,具体取决于元素。
这是一个有趣的方法,但你需要警告这种方法的模块性:将这么多的劳动分配给一个指令只是违反了做一个&#34;纯粹的角度方式的最佳实践&# 34;做的事情。
如果您想继续这个想法,我建议您查看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一个有效的例子。