来自内部ng-transclude的AngularJS父指令范围

时间:2014-12-02 03:43:06

标签: javascript angularjs angularjs-directive

我想打印父指令的ng-repeat迭代器的索引。伪代码:

的index.html

<div data-repeatable>
    {{$index}} does not display
</div>

template.html

<div ng-repeat="i in getTimes(5) track by $index">
    {{$index}} displays correctly
    <div ng-transclude></div>
</div>

app.js

 // Other code omitted
.directive('repeatable', function() {
      return {
        scope: {},
        transclude: true,
        templateUrl: 'template.html'
      };
    })

我已经探索了许多不同的方法/调整,但到目前为止还没有任何工作。任何帮助将不胜感激!

感谢。

1 个答案:

答案 0 :(得分:0)

好吧,所以它可能非常hacky,并依赖AngularJS的内部实现细节,可能会在任何版本中被提取,但仍然......这是我发现的一种方法,可以让它工作。

请注意,这仅适用于Angular 1.3分支。

var app = angular.module('plunker', []);

app.directive('repeatable', function($timeout) {
  return {
    scope: {},
    transclude: true,
    templateUrl: 'template.html',
    link: function(scope, elem, attrs, nullCtrl, transclude) {
      scope.getTimes = function(n) {
        var arr = [];
        for (var i = 1; i <= n; i++) arr.push(i);
        return arr;
      };

      // needs to be done in $applyAsync so the ng-repeat has 
      // time to render all the items
      scope.$applyAsync(function() {
        // using the transclude function just to get hold of the transclude scope
        transclude(function(clone, scope) {
          var ngRepeatScopes = findChildScopesMatching(scope.$parent, isNgRptScope);
          angular.forEach(ngRepeatScopes, function(ngRepeatScope) {
            var transcludedScope = findTranscludedScope(ngRepeatScope);
            transcludedScope.$index = ngRepeatScope.$index;
          });
        });
      });

      function findChildScopesMatching(parentScope, predicateFn) {
        var scopes = [],
          currentScope = parentScope.$$childHead;

        while (currentScope) {
          if (predicateFn(currentScope))
            scopes.push(currentScope);
          currentScope = currentScope.$$nextSibling;
        }
        return scopes;
      }

      function isNgRptScope(scope) {
        return angular.isDefined(scope.$first)
            && angular.isDefined(scope.$last) 
            && angular.isDefined(scope.$index);
      }

      function findTranscludedScope(scope) {
        var transcludedScopes = findChildScopesMatching(scope, isTranscludedScope);
        return transcludedScopes[0] || null;
      }

      function isTranscludedScope(scope) {
        return scope.$$transcluded;
      }
    }
  };
});
.ng-repeat-scope {
  background-color: AliceBlue;
  color: darkblue;
  padding: 5px;
  margin: 5px 0;
}
.ng-transcluded-scope {
  background-color: LightGoldenRodYellow;
  color: GoldenRod;
  padding: 5px;
  margin: 0 20px;
}
.nicer-font {
  font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
  font-size: 14px;
  line-height: 1.42857143;
  padding: 0 10px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.5/angular.min.js"></script>

<div ng-app="plunker" class="nicer-font">
  <div class="container">
    <p>Top level scope ID: {{$id}}</p>
    <div data-repeatable>
      Transcluded scope. $index = {{$index}}. Scope ID: {{$id}}, parent ID: {{$parent.$id}}
    </div>
  </div>

  <script type="text/ng-template" id="template.html">
    <div ng-repeat="i in getTimes(5) track by $index" class="ng-repeat-scope">
      Template ng-repeat scope. $index = {{$index}}. Scope ID: {{$id}}
      <div ng-transclude class="ng-transcluded-scope"></div>
    </div>
  </script>
</div>

如果您愿意,也可以看到相同的演示on Plunkr