Search code examples
angularjsangularjs-ng-repeatangularjs-filter

How do I use ng-filter without changing $index on ng-repeat?


Currently if I filter, the $index also updates. So if there are 500 results, and I filter the ranking, also updates. How do I have an index column that doesn't update?

Here's my code:

<input ng-model="query.teamName" /></div>
<table class="table">
  <thead>
    <tr>
      <th>Rank</th>
      <th>Team</th>
      <th>Location</th>
      <th>Score</th>
    </tr>
  </thead>
  <tbody>
    <tr ng-repeat="team in teams | filter:query | orderBy:orderByScore:reverseSort">
      <td><span style="color:white">{{$index+1}}</span></td>
      <td>{{team.teamName}}</td>
      <td>{{team.teamLocation}}</td>
      <td>{{team.teamPoints | number:2}}</td>
    </tr>
  </tbody>
</table>

Controller:

scoreboard.controller('scoreboardCtrl', function ($scope, $filter) {

     $scope.orderByScore = 'teamPoints';
     $scope.reverseSort = true;

     $scope.teams = [
          { "teamName": "motorboat skydive", "teamLocation": "1189 King", "teamPoints": 35.53},
          { "teamName": "the grinders", "teamLocation": "1189 King", "teamPoints": 127.90},
          { "teamName": "team forrec", "teamLocation": "1189 King", "teamPoints": 29.46},
          { "teamName": "bikini finger", "teamLocation": "1189 King", "teamPoints": 21.98},
          { "teamName": "la familia", "teamLocation": "1189 King", "teamPoints": 148.32},
          { "teamName": "darkness is", "teamLocation": "1189 King", "teamPoints": 108.88},
          { "teamName": "grinders", "teamLocation": "1189 King", "teamPoints": 167.95},
          { "teamName": "discarded youth", "teamLocation": "1189 King", "teamPoints": 55.52}
          ];
     };

Solution

  • Angular filter removes and adds a new array and updates the ng-repeat, so $index will also be updated. Instead you can initialize index, ng-init="idx=$index+1" and use it. ng-init values are never watched and are not updated as well, but $index will change based on the iteration number of the item in the array

    <tr ng-repeat="team in teams  | filter:query | orderBy:orderByScore:reverseSort" ng-init="idx = $index+1">
        <td><span>{{idx}}</span></td>
    

    Plnkr

    Since index is critical here in your case as it is the rankings best way to handle this could be to add index from the controller itself.

    $scope.teams = [
              { "teamName": "motorboat skydive", "teamLocation": "1189 King", "teamPoints": 35.53},
              { "teamName": "the grinders", "teamLocation": "1189 King", "teamPoints": 127.90},
              { "teamName": "team forrec", "teamLocation": "1189 King", "teamPoints": 29.46},
              { "teamName": "bikini finger", "teamLocation": "1189 King", "teamPoints": 21.98},
              { "teamName": "la familia", "teamLocation": "1189 King", "teamPoints": 148.32},
              { "teamName": "darkness is", "teamLocation": "1189 King", "teamPoints": 108.88},
              { "teamName": "grinders", "teamLocation": "1189 King", "teamPoints": 167.95},
              { "teamName": "discarded youth", "teamLocation": "1189 King", "teamPoints": 55.52}
              ]
       .sort(function(itm1, itm2){ return itm2.teamPoints - itm1.teamPoints }) //Sort teams
    
       .map(function(itm, idx){ itm.index = (idx+1); return itm;  }); //assign rankings
    

    I used native sort Or just use angular orderByFilter itself in your controller to do it for the initial set (and remove the logic of ng-init variable assignment from the view). So you don't run with run time $index issues.

    Plnkr2