source

AngularJS: ngIf를 명령어에 프로그래밍 방식으로 추가하는 베스트 프랙티스는 무엇입니까?

ittop 2023. 3. 13. 20:51
반응형

AngularJS: 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 속성이 부가되어 있지만 어떤 이유에서인지 요소에는 적용되지 않고 돔에 존재합니다.그래서 이것은 명백히 잘못된 접근법이다.

이 바이올린은 문제를 나타내고 있습니다.http://jsfiddle.net/L37tZ/2/

왜 이런 일이 일어나는지 누가 설명할 수 있을까요?유사한 행동을 할 수 있는 다른 방법이 있습니까?기존 ngIfs를 고려해야 합니다.

해결책:

사용방법:<div rln-require-roles="['ADMIN', 'USER']">I'm hidden when theses role requirements are not satifisfied!</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;
          }
        }
      });
    }
  };
});

지시문에 우선순위를 추가하는 것이 매우 중요합니다. 그렇지 않으면 해당 요소에 첨부된 다른 지시문은 평가되지 않습니다.

재사용 가능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())Atribute 설정 후, 자신을 컴파일 하고 있기 때문에 스택 오버플로우가 발생하고, 이로 인해 자신을 컴파일 하는 등의 원인이 됩니다.

두 번째는 '어떻게 하면 달성할 수 있을까'입니다.몇 가지 방법을 시도했습니다(내스트된 내용으로 내용을 변환하는 등).ng-if하지만 당신이 원하는 행동을 정확히 이해할 수 없습니다.

다음 단계는 ng-if의 코드를 연구하여 당신의 지시문에 직접 비슷한 것을 구현해 보는 것이 좋을 것 같습니다.

여기 그것을 작동시키기 위한번째 패스입니다.하지만 정말 원하는 대로 작동하려면 약간의 청소와 수정이 필요할 것 같습니다.

템플릿 기능을 사용하여 이 문제를 해결하는 다른 방법이 있습니다.이렇게 하려면 jquery 1.6+가 필요합니다.

코드 조작: http://jsfiddle.net/w72P3/6/

return {
    restrict: 'A',
    replace: true,
    template: function (element, attr) {
        var ngIf = attr.ngIf;
        var value = attr.addCondition;
        /**
         * Make sure to combine with existing ngIf!
         */
        if (ngIf) {
            value += ' && ' + ngIf;
        }
        var inner = element.get(0);
        //we have to clear all the values because angular
        //is going to merge the attrs collection 
        //back into the element after this function finishes
        angular.forEach(inner.attributes, function(attr, key){
            attr.value = '';
        });
        attr.$set('ng-if', value);
        return inner.outerHTML;            
    }
}

합니다.replace: true는 내장요소를 방지합니다. 반환되는 htmlreplace=true에 저장됩니다. , htmlhtml로 반환됩니다.<a href="#" addCondition="'true'">Hello</a> becomes가 되다<a href="#" ng-if="'true'"><a href="#" ng-if="'true'">Hello</a></a>

상세한 것에 대하여는, https://docs.angularjs.org/api/ng/service/$compile 를 참조해 주세요.

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

와 'priority'의terminal: true기본은 다음과 같습니다.터미널 플래그는 Angular에게 동일한 HTML 요소에서 우선순위가 낮은 모든 지시어를 건너뛰도록 지시합니다.

는 이 때문에 .add-conditionng-if를 호출하기 compileng-if기타 지시사항도 있습니다.

언급URL : https://stackoverflow.com/questions/20325480/angularjs-whats-the-best-practice-to-add-ngif-to-a-directive-programmatically

반응형