AngularJS:以编程方式将ngIf添加到指令的最佳做法是什么?

 ren123 发布于 2023-02-13 14:27

我想创建一个指令,根据来自服务的值(例如,检查用户角色)检查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.

解:

用法:

I'm hidden when theses role requirements are not satifisfied!

.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;
          }
        }
      });
    }
  };
});

在指令中添加优先级非常重要,否则不会评估附加到该元素的其他指令!

3 个回答
  • 您可以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.

    2023-02-13 14:29 回答
  • 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只有在您通过身份验证并且&测试输入不为空时,条件才会显示.

    2023-02-13 14:30 回答
  • 问题的第一部分"为什么?"是我能回答的问题:

    您遇到的问题是您无法在不调用元素的情况下动态地将指令应用于元素$compile.

    如果$compile(element)(element.scope())在设置属性后调用,则会遇到堆栈溢出,因为您正在编译自己,导致您自己编译,导致您自己编译等.

    第二部分,"如何实现",我遇到了麻烦.我尝试了几种方法(比如用嵌套转换内容ng-if),但我无法得到你想要的行为.

    我认为下一步可能是研究ng-if的代码并尝试在你的指令中直接实现类似的东西.

    这是让它运转的第一步.我希望它需要一些清理和修改才能让它按照你真正想要的方式工作.

    2023-02-13 14:30 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有