angularjsangularjs-ng-repeatangularjs-digestng-style

Infinite $digest Loop when within an ng-repeat there's an ng-style that calls a function that uses Math


I am trying to dynamically set the background colors of my labels. How I implemented that is to use ng-style like so:

function getColor() {
  return ('#' + Math.floor(Math.random() * 16777215).toString(16));
}
<span ng-repeat='interest in ctrl.profile.interests'      
     class='label interest'
     ng-style="{'background-color': ctrl.getColor()}"> 
     {{ interest }}
</span>

However, whenever I use Math inside getColor, I would get the infinite digest loop error below. Would you have workaround to this problem or a different solution on setting background-color dynamically? Thanks!

10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [ [{"msg":"{'background-color': ctrl.getColor(interest)}","newVal":{"background-color":"#3bf02a"},"oldVal":{"background-color":"#fa8432"}},{"msg":"{'background-color': ctrl.getColor(interest)}","newVal":{"background-color":"#c0a641"},"oldVal":{"background-color":"#bf3c51"}},{"msg":"{'background-color': ctrl.getColor(interest)}","newVal":{"background-color":"#42fa1b"},"oldVal":{"background-color":"#a35769"}},{"msg":"{'background-color': ctrl.getColor(interest)}","newVal":{"background-color":"#d18783"},"oldVal":{"background-color":"#f35b4"}},{"msg":"{'background-color': ctrl.getColor(interest)}","newVal":{"background-color":"#9a0847"},"oldVal":{"background-color":"#ddd27b"}} ], [{"msg":"{'background-color': ctrl.getColor(interest)}","newVal":{"background-color":"#cb0e35"},"oldVal":{"background-color":"#3bf02a"}} ... ]]


Solution

  • You can't have a function in view that returns a different value every time.

    Every digest cycle, Angular does multiple digests until the scope values are stable (the same as last digest). If values in that scope never stabilize you end up with infinite digests and the default limit is 10 before angular aborts.

    I would suggest building an array of random colors in controller first and use $index in ng-repeat to get each value:

    this.randomColors = this.profile.interests.map(function(){
        return ('#' + Math.floor(Math.random() * 16777215).toString(16)); 
    });
    

    Then in view:

    <span ng-repeat='interest in ctrl.profile.interests'      
         class='label interest'
         ng-style="{'background-color': ctrl.randomColors[$index]}"> 
         {{ interest }}
    </span>