0

I would like to bind event listeners on ng-repeat items from within post-link function of "hosting" directive. But during post-link call ng-repeat items are not rendered yet (please see console log in plunker).

After reading article on directive life cycle (https://www.toptal.com/angular-js/angular-js-demystifying-directives) I got an impression, that in post-link all HTML should be already available and ready for adding event listeners.

Is ng-repeat somehow different?

Code:

angular
  .module('myModule', [])
  .directive('myDirective', 
    function() { 
      return {
          scope: { items: '=' },
          restrict: 'E',
          templateUrl: 'myTemplate.html',
          link: function (scope, element) {
              console.log(element.html());
              var anchors = element.find('a');
              console.log(anchors); 
              anchors.on('focus', function() {
                  console.log('I have focus');
              });
          }
      };
    }
  );

Template:

<ul>
  <li ng-repeat="item in items">
    <a href="javascript:;">{{item}}</a>
  </li>
</ul>

Plunker: https://next.plnkr.co/edit/99qi4eliISMeEWD2?preview

georgeawg
  • 48,608
  • 13
  • 72
  • 95
mimo
  • 6,221
  • 7
  • 42
  • 50
  • There are some cases that dom is not ready in link func. You will need to use '$timeout' to ensure that – Bill P Dec 03 '19 at 14:05
  • Thanks Bill, for your suggestion. I've already found out it will work with $timeout, however I wonder, what are cases, when DOM is not available in link and also why. Using $timeout feels a bit hacky to me, although it's definitely quick solution. – mimo Dec 03 '19 at 14:11
  • This might help you - https://stackoverflow.com/questions/13471129/ng-repeat-finish-event – Allabakash Dec 03 '19 at 17:05
  • Thanks Allabakash, I went through answers and found "workarounds". Although I would like to learn why is `ng-repeat` special. – mimo Dec 03 '19 at 21:52

1 Answers1

1

Is ng-repeat somehow different?

The ng-repeat adds and destroys DOM based on data. The .find operation does not find the elements because they have not been yet added to the DOM.

Add the event handler in a directive which is invoked when the framework adds the element to the DOM:

app.directive("myFocus", function() {
    return {
        link: postLink
    };
    function postLink(scope, elem attrs) {
        elem.on('focus', function() {
            console.log('I have focus');
       });
    }
})

Usage

<ul>
  <li ng-repeat="item in items">
    <a my-focus href="javascript:;">{{item}}</a>
  </li>
</ul>

The myFocus directive will add the event handler when the ng-repeat directive add the element to the DOM.

georgeawg
  • 48,608
  • 13
  • 72
  • 95
  • Thanks for the answer, but I have a follow up question. When is DOM pre item added to the page? Is it happening outside directive life cycle functions (compile, controller, pre-link, post-link)? I dodn't find any info on `ng-repeat` docs. – mimo Dec 03 '19 at 22:19