b0bu
b0bu

Reputation: 1222

ng-repeat with *conditional* ng-class by $index

I'm applying a button to a list-group-item using ng-repeat where the button has a class btn-primary when not selected and a minus glyphico and a class btn-success when selected and an ok glyphicon. I'm trying to apply this conditionally using ng-class which is fine, but how to do it by $index selection I don't know. I've looked at examples using the ternary and logic ( && ) operators but can't seem to get the syntax right. To clarify I'd like one button when clicked to change it's icon and it's colour. As you can see I am successfully using the $index to select a group-item and change its colour no problem.

Here's a plunk

http://plnkr.co/edit/dPoHtL7MgFNX4FhDXoBH?p=preview

  <button class="btn btn-sm pull-right move-button" ng-class="{'btn-success': Activatorator, 'btn-primary': !Activatorator}" ng-click="markActive($event, this.$index)">
    <span ng-class="{'glyphicon glyphicon-ok': Activatorator, 'glyphicon glyphicon-minus': !Activatorator}"></span>
  </button>

***** Solution

I fixed this using the selected ng-repeat item as suggested. Since the regular 'class' on an html element sort of acts like the 'else' clause in an if/else I used that to evaluate the default state of the button, btn-primary with glyphicon-minus and ng-class to change the state on click by id.

Working plunker http://plnkr.co/edit/0j9BxFQdD2lIx7lgthDR?p=preview

Upvotes: 2

Views: 3294

Answers (3)

charlietfl
charlietfl

Reputation: 171679

Forget using index and pass the active id to function :

ng-click="setSelected(id)"

$scope.selected ={ id: null}
$scope.setSelected = function(id) {
   $scope.selected.id = id;    
}

$scope.selected is an object so that it will get inherited by the child scopes created in ng-repeat whereas a primitive won't

Then you can compare the id of ng-repeat to selected.id

ng-class="{'list-group-item-info': selected.id == id}"

Upvotes: 2

JB Nizet
JB Nizet

Reputation: 691625

You're using a single scope variable to store the state of 6 different elements. That can't possibly work.

Forget about using the index. That's a bad idea. For example, as soon as you use an orderBy or filter filter, the index of a given element of the array will change. Same if you implement the remove() function; a given element will have its index modified, but you still want its state to be unchanged.

Instead, iterate over objects, and store the state of the object as an attribute of the object. When you click on a button, you change the state of the current object. As simple as that.

Here's a working version of your plunkr: http://plnkr.co/edit/GxI4AyeGBPTDKDFS8Zjf?p=preview

Key stuff:

  $scope.objectsFromServer = [{
    id: 1
  }, 
  {
    id: 2
  }, 
  {
    id: 3
  }, 
  {
    id: 4
  }, 
  {
    id: 5
  }, 
  {
    id: 6
  }];

  $scope.setSelected = function(object) {
    $scope.selectedObject = object
  }

  $scope.markActive = function(object, $event) {
    object.active = !object.active;
    $event.stopPropagation();
    $event.preventDefault();
  };

and

    <li ng-repeat="object in objectsFromServer " ng-click="setSelected(object)" class="list-group-item" ng-class="{'list-group-item-info': object == selectedObject}">{{ object.id }}

      <button disabled="" class="btn btn-sm btn-danger pull-right move-button" ng-click="remove()">
        <span class="glyphicon glyphicon-remove"></span>
      </button>

      <button class="btn btn-sm pull-right move-button" ng-class="{'btn-success': object.active, 'btn-primary': !object.active}" ng-click="markActive(object, $event)">
        <span ng-class="{'glyphicon glyphicon-ok': object.active, 'glyphicon glyphicon-minus': !object.active}"></span>
      </button>

    </li>

Upvotes: 0

Pankaj Parkar
Pankaj Parkar

Reputation: 136124

Basically you need to create a method in scope which will give you the value of activated row.

Markup

<button class="btn btn-sm pull-right move-button" ng-class="{'btn-success': isActivate($index), 'btn-primary': !isActivate($index)}" ng-click="markActive($event, this.$index)">
   <span ng-class="{'glyphicon glyphicon-ok': isActivate($index), 'glyphicon glyphicon-minus': !isActivate($index)}"></span>
</button>

Code

$scope.setSelected = function(idx) {
    $scope.indx = idx;
}

$scope.isActivate =function(idx){
    return $scope.indx == idx
}

Working Plunkr

Though playing with $index of ng-repeat is not an good idea to do, @JB Nizet already given answer for the other way which would be best way to implement it.

Upvotes: 0

Related Questions