Search code examples
angularjsangularjs-ng-repeatangularjs-ng-style

Alternate row color based on previous row/field's value / Improve existing solution


EDIT 2 (ANSWER): For anyone who runs across this looking for a solution to a similar problem, the solution is in the comments under Gianmarco's answer. The productusage array is pre-processed with the same function as the $scope.alternate function below, and the result used to set a isAlternate flag on each item in the array. That is then used in either an ng-style or ng-class attribute to determine which styling to use on the row.

EDIT: For clarity: I have groups of RANames where it might go... RAFoo, RAFoo, RABar, RABar, RABar, RABar, RABaz, RABaz, RABaz etc...and I don't want the row to alternate colors until it hits a new RAName. There is a variable number of RAName values with the same RAName, so there could be 2 "RAFoo", 4 "RABar" and 3 "RABaz", etc.. and it can change up.

I have the following code in my controller:

var prevRAName = ""; // intialize prevRAName to empty string
var switchColor = false; 

...

$scope.alternate = function (currRAName) {
        if (prevRAName) { // starts on 2nd row...
            if (currRAName == prevRAName) {
                prevRAName = currRAName;
            } else {
                switchColor = !switchColor;
                prevRAName = currRAName;
            }

        } else {
            prevRAName = currRAName;  // hits on the first row ...
        }

        return switchColor;
    }

And in the template I have:

<tr ng-repeat="item in productusage | orderBy : ['RAName','PeriodStart']">
    <td ng-style="alternate(item.RAName)  ? {'background-color':'#f5f5f5'} : {'background-color':'white'}">{{item.RAName}}</td>
    <td ng-style="alternate(item.RAName)  ? {'background-color':'#f5f5f5'} : {'background-color':'white'}">{{item.ProductDescription}}</td>
    <td ng-style="{'background-color': '#' + intToRGB(hashCode(item.PeriodStart)), 'color' : 'white'}">{{item.PeriodCaseCt}}</td>
    <td ng-style="{'background-color': '#' + intToRGB(hashCode(item.PeriodStart)), 'color' : 'white'}">{{item.PeriodStart | date : format : shortDate}}</td>
</tr>

I am wanting to alternate the color of the RAName and ProductDescription fields of the table, effectively "grouping" them based on the RAName. The PeriodCaseCt and PeriodCaseCt fields are color coded. Now everything works as is and I wish that this was the end of the story, however I am getting a bunch of these errors:

Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! Watchers fired in the last 5 iterations: [[{"msg":"alternate(item.RAName) ? {'background-color':'#f5f5f5'} : {'background-color':'white'}","newVal":{"background-color":"white"},"oldVal":{"background-color":"#f5f5f5"}}

Now, I don't need these values to be watched after the first pass, and it does correctly set everything and the end user would never know unless they had the developer tools/console tab open, but I know and its bugging the $#%% out of me. How can I improve/fix this?


Solution

  • You can use ng-class-odd and ng-class-even for odd and even elements in a ng-repeat cycle.

    <ol>
      <li ng-repeat="obj in objects">
       <span ng-class-odd="'odd'" ng-class-even="'even'">
         {{obj}}
       </span>
      </li>
    </ol>
    

    The first and all the odds will have the 'odd' class while the even will have the 'even' class.

    Inside each class you can insert whatever you want as attribute.

    In your case you can to something like this:

    <tr ng-repeat="item in productusage | orderBy : ['RAName','PeriodStart']" ng-class-odd="'odd'" ng-class-even="'even'">
        <td>{{item.RAName}}</td>
        <td>{{item.ProductDescription}}</td>
        <td ng-style="{'background-color': '#' + intToRGB(hashCode(item.PeriodStart)), 'color' : 'white'}">{{item.PeriodCaseCt}}</td>
        <td ng-style="{'background-color': '#' + intToRGB(hashCode(item.PeriodStart)), 'color' : 'white'}">{{item.PeriodStart | date : format : shortDate}}</td>
    </tr>
    

    and the CSS would be:

    .odd td{background-color:#f5f5f5}
    .even td{background-color:white}
    

    If you want instead to reach a different result please explain better what you want (maybe with a working example) and I will change my answer