1

I have the following HTML for an ngRepeat element:

<ol id="animationFrame">
  <li ng-repeat="animationImage in animationImages" ng-repeat-listener>
    <img ng-src="{{animationImage.src}}" id="{{animationImage.id}}">
  </li>
</ol>

Within which I want to select based on id using angular.element like this:

angular.element('#animation-image-' + Math.floor($scope.animation.frameImage));

Where $scope.animation.frameImage is rounded down to be an integer. I can see that I am using the correct selector ('#animation-image-1' is the initially loaded selector, for example) and when I change $scope.animation.frameImage using a slider, it works perfectly.

The problem is when the page loads, the angular.element object returned using a correct selector is undefined. Now, I assumed this was because the ng-repeat hasn't populated yet. So I added the following directive for ng-repeat-listener included in the HTML above:

.directive('ngRepeatListener', function() {
  return function(scope) {
    if(scope.$last) {
      scope.$emit('NGREPEATCOMPLETE');
    }
  }

and I use it thusly:

$scope.$on('NGREPEATCOMPLETE', function() {
  console.log(angular.element('#animation-image-1'));
};

which is in fact being called at some point (who knows if it is at the right time or not).

Why isn't this working? How can I fix it?

1 Answer 1

1

ngRepeat isn't rendered until the render phase. To access the element via angular.element(), you could use $evalAsync:

$scope.$evalAsync(function() {  angular.element(...);});

$timeout would also work, but it triggers a digest after the $timeout. If you want access to DOM ready after rendering, and don't want to trigger another digest afterwards, use $evalAsync.

[Edit]

As @maurycy mentioned, $timeout has a second parameter to avoid triggering another digest:

$timeout(function() {...}, 0, false);
Sign up to request clarification or add additional context in comments.

4 Comments

OK, I tried $timeout and $scope.$evalAsync inside my ngCompleteListener directive and neither worked. Does that mean this has to be placed in the controller? Also, would I have to do this every time I call angular.element? If so, this isn't the most elegant solution...
$timeout has a third parameter that's boolean - default true - to call $digest
@ArtlyticalMedia Agreed not elegant. If you need to manipulate the DOM, I would create a directive.
@pixelbits you mean to say that I should create my own directive in place of using <img> tags? I guess I still need to think in directives more when using Angular. I found a work around using a pseudo selector in my CSS but I still think this was a good question to have answered.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.