LatentDenis
LatentDenis

Reputation: 2991

Changing ng-class when clicked (nested ng-repeat)

This is my angular code.. (to describe the problem I'm getting is that the nested ng-repeat for buttons repeats is behavior (when clicked) to all the "jobs" listed..

    <div class="row" ng-repeat="job in jobs">
        <div class="btn-group btn-group-justified" role="group">
             <div class="btn-group" role="group" ng-repeat="status in job.statuscollection">
                   <button type="button" class="btn btn-default" ng-class="{ 'btn-info': $index == selectedIndex }" ng-click="itemClicked($index)">{{status.name}}</button>
             </div>
        </div>
    </div>

Here's my js code..

    $scope.jobs = [
    {
        _id: new Date().toISOString(),
        statuscollection: [
            { name: "Off-Site"},
            { name: "Enroute" },
            { name: "On-Site" },
        ]
        docType: "job",
    },
    {
        _id: new Date().toISOString(),
        statuscollection: [
            { name: "Off-Site"},
            { name: "Enroute" },
            { name: "On-Site" },
        ]
        docType: "job",
    }];

This here's my ng-click function..

    $scope.itemClicked = function ($index) {
         $scope.selectedIndex = $index;
         console.log($scope.jobs[$index]);
    }

I have more than just one job, I included only one here into the code to have less of it. but when the browser generates this data in the correct way, clicking on one of the "job's" buttons does the same thing for each job.

Meaning, if I click the button "on-site" for one job, it is duplicated for all the jobs.. how can I make it so that clicking just one of the job's buttons does it only for that job, and not all of them?

Upvotes: 2

Views: 660

Answers (2)

lux
lux

Reputation: 8436

The proper Angular approach to track indices across multiple ngRepeats is to use ngInit to create a local variable that aliases $index for each instance of ngRepeat. Using $parent to acquire its $index position is generally discouraged.

And in the example below, we have two ngRepeats and therefore two aliased index variables: outerIndex and innerIndex:

  <tbody ng-repeat="country in countries" ng-init="outerIndex = $index">
    <tr ng-repeat="city in country.cities" ng-init="innerIndex = $index">
      <td>{{city}}</td>
      <td>{{country.name}}</td>
      <td>({{outerIndex}}, {{innerIndex}})</td>
    </tr>
  </tbody>

Plunker: http://plnkr.co/edit/VA1XWWrG3pghEcWli06F


Final Edit

After understanding more of the context behind the question, it actually makes more sense for the OP to set an isActive property on the selected object instead attempting to track and match indices. That said the approach noted above is still valid and applicable for tracking indices across multiple ngRepeats

 $scope.itemClicked = function (status, job) {
   if (status.isActive) {
     status.isActive = false;
   } else {
     angular.forEach(job.statuscollection, function(status) {
       status.isActive = false;
     });
     status.isActive = true;
   }
 }

Updated plunker: http://plnkr.co/edit/v70fY30PjoTXCrhOPVZB

Upvotes: 1

Tarun Dugar
Tarun Dugar

Reputation: 8971

Use $parent.$index instead of $index to refer to the outer ng-repeated loop (the job loop, that is):

<button type="button" class="btn btn-default" ng-class="{ 'btn-info': $parent.index == selectedIndex }" ng-click="itemClicked($parent.$index)">{{status.name}}</button>

$index is the index of the inner loop.

$parent.$index is the index of the outer loop.

Upvotes: 1

Related Questions