Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/angularjs/24.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript AngularJS:What';以编程方式将ngIf添加到指令的最佳实践是什么?_Javascript_Angularjs_Angularjs Directive - Fatal编程技术网

Javascript AngularJS:What';以编程方式将ngIf添加到指令的最佳实践是什么?

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,

我想创建一个指令,根据来自服务的值(例如,检查用户角色)检查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中。因此,这显然是一种错误的方法

这把小提琴显示了问题:

谁能解释为什么会发生这种情况?有没有其他方法可以实现类似的行为?应考虑现有的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);
            }
        };
    }