ric*_*rto 3 html javascript angularjs angularjs-directive angular-ui-bootstrap
我正在以角度创建验证指令,我需要在指令绑定的元素中添加工具提示.
通过网络阅读我发现这个解决方案设置了一个高优先级和终端指令,但由于我使用的是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);
}
};
},
}
Run Code Online (Sandbox Code Playgroud)
但这对我不起作用.它会引发以下错误:
错误:[$ 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" >
Run Code Online (Sandbox Code Playgroud)
关于如何解决这个问题的任何想法?
谢谢.
原因是您的指令priority与terminal选项的组合.这意味着ngModel指令根本不会呈现.由于您的指令priority(1000)大于ng-model(0),并且terminal选项的存在不会呈现任何其他具有较低优先级(超过1000)的指令.所以一些可能的选择是:
ngModel:"="(根据您的要求).tooltip您可以在指令中使用transclusion并使用指令模板,而不是添加属性并重新编译元素.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);
}
};
},
}
})Run Code Online (Sandbox Code Playgroud)
<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>Run Code Online (Sandbox Code Playgroud)
正如我在评论中所解释的那样,您不需要重新编译元素和所有这些内容,只需设置一个元素并将其追加到目标元素之后(在您的特定情况下,输入).
这是验证指令的修改版本(我没有实现任何验证细节,我相信你应该能够轻松连接).
所以你需要的是为工具提示设置自定义触发器,你可以使用$tooltipprovider.因此,当您想要显示/隐藏工具提示时,请设置一个事件对.
.config(function($tooltipProvider){
$tooltipProvider.setTriggers({'show-validation':'hide-validation'});
});
Run Code Online (Sandbox Code Playgroud)
现在,在您的指令中,只需使用工具提示属性设置工具提示元素即可.仅编译tooltip元素并将其追加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;
}
}
};
},
}
});
Run Code Online (Sandbox Code Playgroud)
内联演示
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'
});
});Run Code Online (Sandbox Code Playgroud)
/* Put your css in here */
.validation {
display: block;
}Run Code Online (Sandbox Code Playgroud)
<!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>Run Code Online (Sandbox Code Playgroud)