4

I write below directive to make call a function when ngRepeat element gets rendered on UI.

Directive

directives.directive('repeatDone', function() {
    return {
        restrict: 'A',
        require: 'ngRepeat',
        link: function(scope, element, attrs, ngModel) {
            if (scope.$last) {
                scope.$eval(attrs.repeatDone);
            }
        }
    };
});

But it is giving $compile error. If I remove require part, it works OK.

Why AngularJS can not accept "require: 'ngRepeat'"? Help would appreciated.

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299
stevenfrog
  • 83
  • 6

2 Answers2

7

require is used for accessing the controller of another directive. But ng-repeat does not have a controller. Take a look at the source for ng-repeat, the word controller doesn't even appear in the code. The documentation also makes no mention of a controller for ng-repeat.

Typically, when you use require it's because you want to call functions of the required controller. In the link function for your directive you've added the argument ngModel -- which is what would be populated with the controller if it existed. But you never use this ngModel argument in the code. It's not really clear why you need to use require at all in this case.

EDIT:

On further review, perhaps you're trying to require ng-repeat because your repeat-done directive won't work outside the context of an ng-repeat. If that's the reason, another solution might be to traverse the DOM looking at the parent elements of your repeat-done directive to see if they have the attribute 'ng-repeat'. If not found, your directive could throw an error. But that seems like a lot more code w/little return on investment...

Sunil D.
  • 17,983
  • 6
  • 53
  • 65
  • 1
    Good answer. I think the face meaning of "require" make me confused. **"require" in directive means need a controller or ngModel for next steps, not this directive must be used related to something.** – stevenfrog Feb 08 '15 at 04:45
2

You should you $timeout before evaluating a scope. Because when you write code inside timeout, $timeout will run exactly after current digest cycle gets complete.

Or you can use scope.$evalAsync instead of scope.$eval

$timeout which implicitly calls $apply() after a delay & $apply runs $digest cycle call exactly after DOM redered element on browser

$evalAsync maintain async queue, and gets called after digest cycle call exactly before DOM redered element on browser

CODE

directives.directive('repeatDone', function($timeout) {
    return {
        restrict: 'A',
        link: function(scope, element, attrs, ngModel) {
            if (scope.$last) {
                $timeout(function () {
                    scope.$eval(attrs.repeatDone);
                });
                //or you can use 
                //scope.$evalAsync(attrs.repeatDone);
            }
        }
    };
});

Thanks.

Pankaj Parkar
  • 134,766
  • 23
  • 234
  • 299