[英]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.