Search code examples
javascriptjqueryangularjsng-styleangularjs-rootscope

AngularJS: $rootScope:infdig error when calling a ng-style function inside ng-repeat


I'm trying to build an animation on some phrases that will be displayed on the site main page, in a random position and with fade and translate effects.

I would achieve this using ng-style attribute inside an ng-repeat attribute and setting the ng-style value calling a JavaScript function defined inside the HomeController.

Using this approch cause angular to throw the exception: $rootScope:infdig error 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations

I read so much about this but no solution has solved my case. Anyone could help me?

Here is a part of index.html:

<div class="phrasesContainer" animate-phrases="">
      <h3 class="flying-text" ng-repeat="phrase in Phrases" ng-style="getTopLeftPosition()">{{phrase}}</h3>
    </div>

Here is the controller function:

$scope.getTopLeftPosition = function() {
var top = randomBetween(10, 90);
var left = getRandomTwoRange(5, 30, 70, 80);

return {
  top: top + '%',
  left: left + '%'
};

}

Here is a demo: http://plnkr.co/edit/8sYks589agtLbZCGJ08B?p=preview


Solution

  • Here's a solution where I moved your style generation into the directive. The position is being set right before showing the element. Since this is a CSS change, I modified the styling as well so that the position does not transition.

    Here's the directive. The code I've excluded has not been changed:

    app.directive('animatePhrases', function() {
      return {
        restrict: 'A',
        link: function(scope, element, attrs) {
          setTimeout(function() {
            ...
          }, 1000);
    
          function changeText() {
            var currentActive = $('.phrasesContainer .active');
            var nextActive = currentActive.next();
            currentActive.toggleClass('active');
    
            if (nextActive.length == 0)
              nextActive = $('.phrasesContainer .flying-text').first();
    
            nextActive.css(getTopLeftPosition()); // Add this
            nextActive.toggleClass('active');
    
            setTimeout(changeText, 5000);
          }
    
          function getTopLeftPosition() {
            ...
          }
    
          function getRandomTwoRange(firstStart, firstEnd, secondStart, secondEnd) {
            ...
          }
    
          function randomBetween(min, max) {
            ...
          }
        }
      };
    });
    

    CSS:

    .flying-text {
        transition: opacity 2s ease-in-out, margin 2s ease-in-out;
        position: absolute;
        opacity: 0;
        font-size: 1.5em;
    }
    

    In your HTML, simply remove the ng-style.

    Plunker: http://plnkr.co/edit/bZB3A5hD7Bc4r4pp1g7V?p=preview