我正在以角度创建验证指令,我需要在指令绑定的元素中添加工具提示。
通过网络阅读我发现这个解决方案设置了一个高优先级和终端指令,但由于我使用的是ngModel,这对我不起作用。这就是我现在正在做的事情:
return {
restrict: 'A',
require: 'ngModel',
replace: false,
terminal: true,
priority: 1000,
scope: {
model: '=ngModel',
initialValidity: '=initialValidity',
validCallback: '&',
invalidCallback: '&'
},
compile: function compile(element, attrs) {
element.attr('tooltip', '{{validationMessage}');
element.removeAttr("validator");
return {
post: function postLink(scope, element) {
$compile(element)(scope);
}
};
},
}
但它不适合我。它会引发以下错误:
错误:[$ compile:ctreq]无法找到指令'validator'所需的控制器'ngModel'!
这是我正在使用该指令的HTML:
<input id="username" name="username" data-ng-model="user.username" type="text" class="form-control" validator="required, backendWatchUsername" placeholder="johndoe" tabindex="1" >
关于如何解决这个问题的任何想法?
感谢。
答案 0 :(得分:5)
原因是您的指令priority
与 terminal
选项相结合。这意味着ngModel
指令根本不会呈现。由于您的指令优先级(1000
)大于ng-model(0
),并且terminal
选项的存在不会呈现任何其他具有较低优先级(超过1000)的指令。所以一些可能的选择是:
ngModel:"="
(根据您的要求)。tooltip
属性并重新编译元素。terminal - 如果设置为true,则当前优先级将是将执行的最后一组指令(当前优先级的任何指令仍将执行,因为未定义相同优先级的执行顺序)。请注意,指令模板中使用的表达式和其他指令也将被排除在执行之外。
<强>演示强>
angular.module('app', []).directive('validator', function($compile) {
return {
restrict: 'A',
require: 'ngModel',
replace: false,
terminal: true,
scope: {
model: '=ngModel',
initialValidity: '=initialValidity',
validCallback: '&',
invalidCallback: '&'
},
compile: function compile(element, attrs) {
element.attr('tooltip', '{{validationMessage}');
element.removeAttr("validator");
return {
post: function postLink(scope, element) {
$compile(element)(scope);
}
};
},
}
})
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
<input validator ng-model="test">
</div>
正如我在评论中所解释的那样,您不需要重新编译元素和所有这些内容,只需设置一个元素并将其附加到目标元素之后(在您的特定情况下,输入)。
这是验证指令的修改版本(我没有实现任何验证细节,我相信你应该能够轻松连接)。
所以你需要的是为工具提示设置自定义触发器,你可以使用$tooltipprovider
来完成。因此,当您想要显示/隐藏工具提示时,请设置一个事件对。
.config(function($tooltipProvider){
$tooltipProvider.setTriggers({'show-validation':'hide-validation'});
});
现在在你的指令中,只需使用工具提示属性就可以设置工具提示元素。仅编译工具提示元素并将其附加到目标元素after
(您可以使用css ofcourse管理定位)。当您有验证失败时,只需获取tooltip element reference
(这是对工具提示元素的引用,而不是复制每次使用选择器时都可以选择的引用)并执行$tooltipEl.triggerHandler('show-validation')
并隐藏它$tooltipEl.triggerHandler('show-validation')
。
示例实现,显示2秒后的工具提示,并在5秒后隐藏它(因为验证不在此问题的范围内,您应该能够连接它):
.directive('validator', function($compile, $timeout){
var tooltiptemplate = '<span class="validation" tooltip="{{validationMessage}}" tooltip-trigger="show-validation" tooltip-placement="bottom"></span>';
var tooltipEvents = {true:'show-validation', false:'hide-validation'};
return {
restrict: 'A',
require: 'ngModel',
replace: false,
priority: 1000,
scope: {
model: '=ngModel',
initialValidity: '=initialValidity',
validCallback: '&',
invalidCallback: '&'
},
compile: function compile(element, attrs) {
return {
post: function postLink(scope, element) {
var $tooltipEl= getTooltip();
init();
function init(){
scope.$on('$destroy', destroy);
scope.validationMessage ="Whoops!!!";
$timeout(function(){
toggleValidationMessage(true);
},2000);
$timeout(function(){
toggleValidationMessage(false);
},5000);
}
function toggleValidationMessage(show){
$tooltipEl.triggerHandler(tooltipEvents[show]);
}
function getTooltip(){
var elm = $compile(angular.element(tooltiptemplate))(scope);
element.after(elm);
return elm;
}
function destroy(){
$tooltipEl= null;
}
}
};
},
}
});
<强> Plnkr 强>
内联演示
var app = angular.module('plunker', ['ui.bootstrap']);
app.controller('MainCtrl', function($scope) {
$scope.user = {
username: 'jack'
};
}).directive('validator', function($compile, $timeout) {
var tooltiptemplate = '<span class="validation" tooltip="{{model}}" tooltip-trigger="show-validation" tooltip-placement="bottom"></span>';
var tooltipEvents = {
true: 'show-validation',
false: 'hide-validation'
};
return {
restrict: 'A',
require: 'ngModel',
replace: false,
priority: 1000,
scope: {
model: '=ngModel',
initialValidity: '=initialValidity',
validCallback: '&',
invalidCallback: '&'
},
compile: function compile(element, attrs) {
return {
post: function postLink(scope, element) {
var $tooltipEl = getTooltip();
init();
function init() {
scope.$on('$destroy', destroy);
scope.validationMessage = "Whoops!!!";
$timeout(function() {
toggleValidationMessage(true);
}, 2000);
$timeout(function() {
toggleValidationMessage(false);
}, 5000);
}
function toggleValidationMessage(show) {
$tooltipEl.triggerHandler(tooltipEvents[show]);
}
function getTooltip() {
var elm = $compile(angular.element(tooltiptemplate))(scope);
element.after(elm);
return elm;
}
function destroy() {
elm = null;
}
}
};
},
}
}).config(function($tooltipProvider) {
$tooltipProvider.setTriggers({
'show-validation': 'hide-validation'
});
});
/* Put your css in here */
.validation {
display: block;
}
<!DOCTYPE html>
<html ng-app="plunker">
<head>
<meta charset="utf-8" />
<title>AngularJS Plunker</title>
<link data-require="bootstrap-css@3.1.*" data-semver="3.1.1" rel="stylesheet" href="//netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css" />
<script>
document.write('<base href="' + document.location + '" />');
</script>
<script data-require="angular.js@1.3.x" src="https://code.angularjs.org/1.3.12/angular.js" data-semver="1.3.12"></script>
<script data-require="ui-bootstrap@*" data-semver="0.12.0" src="http://angular-ui.github.io/bootstrap/ui-bootstrap-tpls-0.12.0.min.js"></script>
</head>
<body ng-controller="MainCtrl">
<br/>
<br/>{{user.username}}
<input id="username" name="username" data-ng-model="user.username" type="text" class="form-control" validator="required, backendWatchUsername" placeholder="johndoe" tabindex="1">
</body>
</html>
答案 1 :(得分:0)
你不应该在你的指令中创建一个新的隔离范围:这将搞乱其他指令(在这种情况下不会共享ngModel)。
return {
restrict: 'A',
require: 'ngModel',
compile: function compile(element, attrs) {
element.attr('tooltip', '{{validationMessage}');
element.removeAttr("validator");
return {
post: function postLink(scope, element) {
$compile(element)(scope);
}
};
},
}
我邀请您查看Angular-UI库,特别是他们如何实现ui.validate指令:http://angular-ui.github.io/ui-utils/