我想创建一个指令,根据来自服务的值(例如,检查用户角色)检查dom中是否应该存在元素.
相应的指令如下所示:
angular.module('app', []).directive('addCondition', function($rootScope) { return { restrict: 'A', compile: function (element, attr) { var ngIf = attr.ngIf, value = $rootScope.$eval(attr.addCondition); /** * Make sure to combine with existing ngIf! * I want to modify the expression to be evalued by ngIf here based on a role * check for example */ if (ngIf) { value += ' && ' + ngIf; } attr.$set('ng-if', value); } }; });
最后,元素附加了ng-if属性,但不知何故,它不适用于元素,它仍然存在于dom中.所以这显然是一种错误的做法.
这个小提琴显示了问题:http://jsfiddle.net/L37tZ/2/
谁能解释为什么会这样?有没有其他方式可以实现类似的行为?应考虑现有的ngIfs.
解:用法:
.directive('rlnRequireRoles', function ($animate, Session) { return { transclude: 'element', priority: 600, terminal: true, restrict: 'A', link: function ($scope, $element, $attr, ctrl, $transclude) { var block, childScope, roles; $attr.$observe('rlnRequireRoles', function (value) { roles = $scope.$eval(value); if (Session.hasRoles(roles)) { if (!childScope) { childScope = $scope.$new(); $transclude(childScope, function (clone) { block = { startNode: clone[0], endNode: clone[clone.length++] = document.createComment(' end rlnRequireRoles: ' + $attr.rlnRequireRoles + ' ') }; $animate.enter(clone, $element.parent(), $element); }); } } else { if (childScope) { childScope.$destroy(); childScope = null; } if (block) { $animate.leave(getBlockElements(block)); block = null; } } }); } }; });
在指令中添加优先级非常重要,否则不会评估附加到该元素的其他指令!
您可以ngIf
在自己的指令中重用,如下所示:
/** @const */ var NAME = 'yourCustomIf';
yourApp.directive(NAME, function(ngIfDirective) {
var ngIf = ngIfDirective[0];
return {
transclude: ngIf.transclude,
priority: ngIf.priority,
terminal: ngIf.terminal,
restrict: ngIf.restrict,
link: function($scope, $element, $attr) {
var value = $attr[NAME];
var yourCustomValue = $scope.$eval(value);
$attr.ngIf = function() {
return yourCustomValue;
};
ngIf.link.apply(ngIf, arguments);
}
};
});
然后像这样使用它
<div your-custom-if="true">This is shown</div>
它将使用随附的所有"功能" ngIf
.
Joscha的答案相当不错,但实际上如果你使用ng-if,这将不起作用.我拿了Joscha的代码并添加了几行来将它与现有的ng-if指令结合起来:
angular.module('myModule').directive('ifAuthenticated', ['ngIfDirective', 'User', function(ngIfDirective, User) { var ngIf = ngIfDirective[0]; return { transclude: ngIf.transclude, priority: ngIf.priority - 1, terminal: ngIf.terminal, restrict: ngIf.restrict, link: function(scope, element, attributes) { // find the initial ng-if attribute var initialNgIf = attributes.ngIf, ifEvaluator; // if it exists, evaluates ngIf && ifAuthenticated if (initialNgIf) { ifEvaluator = function () { return scope.$eval(initialNgIf) && User.isAuthenticated(); } } else { // if there's no ng-if, process normally ifEvaluator = function () { return User.isAuthenticated(); } } attributes.ngIf = ifEvaluator; ngIf.link.apply(ngIf, arguments); } }; }]);
那么如果可以做以下事情:
<input type="text" ng-model="test"> <div ng-if="test.length > 0" if-authenticated>Conditional div</div>
div
只有在您通过身份验证并且&测试输入不为空时,条件才会显示.
问题的第一部分"为什么?"是我能回答的问题:
您遇到的问题是您无法在不调用元素的情况下动态地将指令应用于元素$compile
.
如果$compile(element)(element.scope())
在设置属性后调用,则会遇到堆栈溢出,因为您正在编译自己,导致您自己编译,导致您自己编译等.
第二部分,"如何实现",我遇到了麻烦.我尝试了几种方法(比如用嵌套转换内容ng-if
),但我无法得到你想要的行为.
我认为下一步可能是研究ng-if的代码并尝试在你的指令中直接实现类似的东西.
这是让它运转的第一步.我希望它需要一些清理和修改才能让它按照你真正想要的方式工作.