2

The html looks like:

<div ng-controller="MainCtrl">
    <outer>
      <inner ng-repeat="d in data">
        <div>{{d}}</div>
      </inner>
    </outer>
</div>

The repeat works, and the inner-directive is applied as expected.

The outer-directive looks like:

directives.directive('outer', function () {
    return {
        compile: function (elm) {
           // ... do some jQuery
        }
    }
});

Without the repeat, the outer-directive is applied as expected. But with the repeat, the outer-directive is applied before the repeat writes the appropriate nodes to the DOM.

I've seen suggestions to use timeout within the directive, which seems a bit of a hack to me. Additionally it looks like there is a finished-repeat hook that I could use to then alter scope and reapply the directive.

Robert Christian
  • 18,218
  • 20
  • 74
  • 89
  • This SO post would help you http://stackoverflow.com/questions/15207788/calling-a-function-when-ng-repeat-has-finished – Chandermani Oct 29 '13 at 03:59
  • @Chandermani - Thanks. I tried adding to the inner-directive: if (scope.$last === true){ $timeout(function () {scope.finished = true;});}, and then watch from the outer-directive. The scope changes, but triggers on the first element not the last. – Robert Christian Oct 29 '13 at 04:22
  • You should not do `scope.finished=true;` inside your child directive. This sets the local scope.You should `$scope.$emit` to raise an event. – Chandermani Oct 29 '13 at 05:08

2 Answers2

0

Here is how I solved it:

HTML:

<!doctype html>
<html ng-app="myApp">

<head>
  <meta charset="utf-8">
  <title>AngularJS Plunker</title>
  <script>
    document.write('<base href="' + document.location + '" />');
  </script>
  <link rel="stylesheet" href="style.css">
  <script data-require="angular.js@1.0.x" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.6/angular.js"></script>
  <script src="app.js"></script>
</head>
<body>

  <div ng-controller="MainCtrl">
    <outer>
      <inner ng-repeat="d in data">
        <div>{{d}}</div>
      </inner>
    </outer>
  </div>
</body>

</html>

App.js:

var myApp = angular.module('myApp', ['myApp.directives']);

myApp.controller('MainCtrl', function($scope) {
  $scope.data = [1, 2, 3];
});

var directives = angular.module('myApp.directives', []);

directives.directive('inner', function() {

  return {
        restrict: 'E',
        scope: true,
        link: function(scope, element, attrs) {
            element.append("<div>Processing inner element.</div>");
            if (scope.$last) {
              element.append("Processed last inner element.");
              scope.$emit('foo', "");
            }
        }
  }      
});

directives.directive('outer', function() {
  return {
        restrict: 'E',
        scope: true,
        link: function(scope, element, attrs) {
            scope.$on('foo', function() {
              element.append("<div>Finished outer processing.</div>");
              element.append(element.getChildren());
              // this is critical if jQuery altered DOM in inner directive
              scope.$apply();
            });
        }
  }      
});

Output:

1
Processing inner element.
2
Processing inner element.
3
Processing inner element.
Processed last inner element.
Finished outer processing.

Plunker: http://plnkr.co/edit/tMXq7fFeNLnDbn9ORdUS

@Chandermani - Thanks for the nudge!

Robert Christian
  • 18,218
  • 20
  • 74
  • 89
-1

My suggestion is to handle the repeat inside your directive template.

directives.directive('outer-directive', function () {
return {
    template:"<div ng-repeat='d in data'>"
                 + "<innerDirective id={{d.id}} text={{d.text}} />"
              +"</div>",
    controller: function ($scope, $element, $attrs){
           $scope.data = getData();
    }
    compile: function (elm) {
       // ... do some jQuery
    }
}
});
Chris Wu
  • 57
  • 6