Javascript AngularJS:What';以编程方式将ngIf添加到指令的最佳实践是什么?
我想创建一个指令,根据来自服务的值(例如,检查用户角色)检查dom中是否应该存在元素 相应的指令如下所示:Javascript AngularJS:What';以编程方式将ngIf添加到指令的最佳实践是什么?,javascript,angularjs,angularjs-directive,Javascript,Angularjs,Angularjs Directive,我想创建一个指令,根据来自服务的值(例如,检查用户角色)检查dom中是否应该存在元素 相应的指令如下所示: angular.module('app', []).directive('addCondition', function($rootScope) { return { restrict: 'A', compile: function (element, attr) { var ngIf = attr.ngIf,
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中。因此,这显然是一种错误的方法
这把小提琴显示了问题:
谁能解释为什么会发生这种情况?有没有其他方法可以实现类似的行为?应考虑现有的NGIF
解决方案:
用法:当这些角色要求未得到满足时,我将被隐藏代码>
在指令中添加优先级非常重要,否则附加到该元素的其他指令不会被计算 你问题的第一部分“为什么?”,我可以回答:
您遇到的问题是,如果不在元素上调用$compile
,就无法对元素动态应用指令
如果在设置属性后调用$compile(element)(element.scope())
,则会因为您自己编译而遇到堆栈溢出,这会导致您自己编译,从而导致您自己编译,等等
第二部分,“如何实现”,我遇到了麻烦。我尝试了几种方法(比如用嵌套的ng if
)来屏蔽内容),但我无法准确地得到您想要的行为
我认为下一步可能是研究的代码,并尝试直接在指令中实现类似的东西
这是一本书。我希望它需要一些清理和修改,以使它按照您真正想要的方式工作。还有另一种方法可以解决这个问题,使用模板函数。这需要jQuery1.6+才能正常工作
代码的一把小提琴:
替换:true可防止嵌入元素。如果没有replace=true,则模板函数返回的字符串将放在现有html中。也就是说,
变成了
有关详细信息,请参见$compile。您可以在自己的指令中重复使用ngIf
,如下所示:
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);
}
};
});
/**@const*/var NAME='yourCustomIf';
yourApp.directive(名称、功能(ngIfDirective){
var ngIf=ngIfDirective[0];
返回{
转移:ngIf.transclude,
优先级:ngIf.priority,
航站楼:ngIf.terminal,
限制:ngIf.restrict,
链接:函数($scope、$element、$attr){
var值=$attr[NAME];
var yourCustomValue=$scope.$eval(值);
$attr.ngIf=函数(){
返回您的自定义值;
};
ngIf.link.apply(ngIf,参数);
}
};
});
然后像这样使用它
显示了这一点
它将使用使用ngIf
所附带的所有“功能”,Joscha的答案非常好,但实际上,如果您在使用ng if的同时使用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
只有在您经过身份验证且测试输入不为空时,才会显示条件div
return {
restrict: 'A',
terminal: true,
priority: 50000, // high priority to compile this before directives of lower prio
compile: function compile(element, attrs) {
element.removeAttr("add-condition"); // avoid indefinite loop
element.removeAttr("data-add-condition");
return {
pre: function preLink(scope, iElement, iAttrs, controller) { },
post: function postLink(scope, iElement, iAttrs, controller) {
iElement[0].setAttribute('ng-if', iAttrs.addCondition);
$compile(iElement)(scope);
}
};
}
高优先级和terminal:true
的组合是其工作原理的基础:terminal标志告诉Angular跳过同一HTML元素上所有低优先级的指令
这很好,因为我们希望在调用compile
之前,通过将add condition
替换为ng if
来修改元素,然后将处理ng if
和任何其他指令。感谢您的解释!我会尽力让你的方法奏效!它是这样工作的,我只更改了一些内容,比如观察表达式和该指令运行的优先级。当您还需要对元素执行其他指令时,优先级非常重要。谢谢我认为这是一种比公认答案更好的方法,因为它非常通用,并且使用了“真正的”ngIf指令。没有重复的指令代码,如果ngIf在将来发生更改(可能是由于错误修复/改进),这将自动利用它。最后一行中的“参数”是什么?@KumarSambhav与传递给自定义if函数的参数相同-它们只是传递给原始ngIf。@Joscha此解决方案非常好,但是,如果您试图将console.log放入$attr.ngIf=function{//log here},您将看到此方法已被多次调用,原因是什么?解决方案是什么?请?.ngIf=ngIfDirective[0];->很遗憾我们不得不这么做?有人能解释一下原因吗?它是有效的,除了一个同级指令不会转包(例如ng消息)。它如何与两个自定义指令一起工作?我是说我写的两条指令?@Mark如果你把这段代码分成两条指令,并把两条指令放在一个DOM元素上,angular将根据优先级顺序执行这两条指令。因为这段代码和ng if一起检查,所以最终会将这两个条件应用于元素。请注意,我还没有测试过这个功能,唯一的一个小缺陷是使用了不推荐使用的replace:true
功能非常好,但是没有参考最后一行中的getBlockElements
什么是“arguments”?在JS中,arguments是一个类似数组的对象,包含函数的参数。这里,参数是[范围、元素、属性,…]
其中。。。是angular传递给链接函数的参数,即使它们没有注入到我自己的链接函数中。你可以在作品中找到解释和例子,非常好,谢谢。但是我正在尝试访问应用自定义指令的元素,没有运气element
似乎是有角度的注释,element[0]。nextElementSibling
是
return {
restrict: 'A',
terminal: true,
priority: 50000, // high priority to compile this before directives of lower prio
compile: function compile(element, attrs) {
element.removeAttr("add-condition"); // avoid indefinite loop
element.removeAttr("data-add-condition");
return {
pre: function preLink(scope, iElement, iAttrs, controller) { },
post: function postLink(scope, iElement, iAttrs, controller) {
iElement[0].setAttribute('ng-if', iAttrs.addCondition);
$compile(iElement)(scope);
}
};
}