AngularJS:以编程方式将 ngIf 添加到指令的最佳实践是什么? [英] AngularJS: What's the best practice to add ngIf to a directive programmatically?
问题描述
我想创建一个指令,根据来自服务的值(例如检查用户角色)检查元素是否应存在于 dom 中.
I want to create a directive that checks if an element should be present in the dom based on a value coming from a service (e.g. check for a user role).
相应的指令如下所示:
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 中.所以这显然是一种错误的做法.
At the end the element has the ng-if attribute attached but somehow it doesn't apply to the element and it is still existing in the dom. So this is obviously a wrong approach.
这个小提琴显示了问题:http://jsfiddle.net/L37tZ/2/
This fiddle shows the problem: http://jsfiddle.net/L37tZ/2/
谁能解释为什么会这样?有没有其他方法可以实现类似的行为?应考虑现有的 ngIf.
Who can explain why this happens? Is there any other way a similar behaviour could be achieved? Existing ngIfs should be considered.
用法:<div rln-require-roles="['ADMIN', 'USER']">当这些角色要求不满足时我会隐藏!</div>
.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;
}
}
});
}
};
});
在指令中添加优先级非常重要,否则附加到该元素的其他指令不会被评估!
It is very important to add the priority in the directive, otherwise other directives attached to that element are not evaluated!
推荐答案
你问题的第一部分,为什么?",我可以回答:
The first part of your question, "why?", is something I can answer:
您遇到的问题是,如果不对元素调用 $compile
,就无法将指令动态应用于元素.
The problem you are running into is that you can't dynamically apply directives to elements without calling $compile
on the element.
如果在设置属性后调用 $compile(element)(element.scope())
,则会遇到堆栈溢出,因为您正在编译自己,这会导致您自己编译导致你自己编译等
If you call $compile(element)(element.scope())
after you set the attribute, you run into a stack overflow because you are compiling yourself, which cause you to compile yourself which causes you to compile yourself, etc.
第二部分,如何实现",我遇到了麻烦.我尝试了几种方法(例如使用嵌套的 ng-if
转换内容),但我无法准确获得您正在寻找的行为.
The second part, "how else to achieve", I am having trouble with. I tried a couple of approaches (like transcluding the content with a nested ng-if
) but I can't get exactly the behavior you are looking for.
我认为下一步可能是研究 ng-if 并尝试直接在您的指令中实现类似的东西.
I think the next step might be to study the code for ng-if and try to implement something similar directly in your directive.
这是让它工作的第一遍.但是,我希望它需要进行一些清理和修改才能使其按照您真正想要的方式工作.
Here is a first pass of getting it working. I expect it needs some cleanup and modification to get it working how you really want it, however.
这篇关于AngularJS:以编程方式将 ngIf 添加到指令的最佳实践是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!