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
@Hieu Le hinted to the problem, but your issue is that since you are always returning a random position in your getTopLeftPosition
function, angularjs digest loop will get called every time to actually propagate the changes to the watchers. This caused it to keep running over and over.
What you can do is to pre-calculate your random positions and then use that in your html.
For example, in your activate function you can do something like this:
function activate() {
$scope.Phrases = ["Phrase 1", "Phrase 2", "Phrase 3", "Phrase 4", "Phrase 5", "Phrase 6"];
$scope.PhrasesAndPositions = $scope.Phrases.map(function(phrase){
return {
phrase: phrase,
position: getTopLeftPosition()
}
});
}
And then you can change your html to something like this:
<div class="phrasesContainer" animate-phrases="">
<h3 class="flying-text" ng-repeat="pap in PhrasesAndPositions" ng-style="pap.position">{{pap.phrase}}</h3>
</div>
Here is the working plunk with my changes: http://plnkr.co/edit/FD9hYX9Q5wUkW2q7y86M?p=preview
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With