由于您的指令
priority
结合了
terminal
选项,这就是为什么
ngModel
指令根本不会渲染的原因。因为您的指令优先级(
1000
)大于 ng-model 的优先级(
0
),而且存在
terminal
选项将不会渲染任何其他优先级低于 1000 的指令。所以有一些可能的选择:
- 从您的指令中删除 terminal 选项或
- 将您的指令优先级降低到 0 或 -1(小于等于 ngModel)或
- 从指令中删除 ng-model 要求,并可能使用双向绑定,例如
ngModel:"="
(根据您的要求)。
- 除了添加 tooltip 属性并重新编译元素之外,您可以在指令中使用 transclusion 并具有指令模板。
终端 - 如果设置为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'});
});
在您的指令中,只需将提示工具元素设置为您喜欢的样式,并在其上设置提示工具属性。只编译提示工具元素并将其附加到目标元素之后(当然可以使用css进行定位)。当验证失败时,只需获取提示工具元素的引用(这是对提示工具元素的引用,而不是复制引用,您也可以每次使用选择器进行选择),然后执行$tooltipEl.triggerHandler('show-validation')进行显示,执行$tooltipEl.triggerHandler('hide-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'
});
});
.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>