Spialdor
Spialdor

Reputation: 1645

AngularJS give active class to button in button group

I have a button group with some buttons, two created with html and others are created with a ng-repeat. I want that on click the button have an active class so I can custom it to show it's activated.

So here is what I do :

<div class="btn-group" role="group" aria-label="Basic example"
     ng-init="selectedTab = 'raw'">

  <button class="btn"
     ng-click="selectView('raw'); selectedTab = 'raw'; console.log(selectedTab);"
     ng-class="{'active':selectedTab === 'raw'}">Raw data
  </button>
  <button class="btn"
     ng-click="selectView('summary'); selectedTab = 'summary'; console.log(selectedTab);"  
     ng-class="{'active':selectedTab === 'summary'}">Summary
  </button>

  <button class="btn" ng-repeat="(key, value) in views"
          ng-click="selectView(key); selectedTab = key; console.log(selectedTab);"
          ng-class="{'active':selectedTab === key}">
    {{ key }}
  </button>
</div>

My problem is that for the two first one all works fine, when I click on the first button the class active is added, and when I click on the second the class is removed from the first one and added to the second one.

The problem is about the buttons generated by the ng-repeat, when I click on them it's add the active class to the button but when I click on another button it's not removing the class, so they can all have the activate class.

What am I doing wrong ?

Upvotes: 0

Views: 1985

Answers (2)

georgeawg
georgeawg

Reputation: 48968

New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view, ng-include and ng-if all create new child scopes, so the problem often shows up when these directives are involved.

The assignment selectedTab = key is being done on the child scope created by the ng-repeat directive. The solution is to do the assignment to a property of an object:

<div class="btn-group" role="group" aria-label="Basic example"
     ng-init="selected = {tab:'raw'}">

  <button class="btn"
     ng-click="selectView('raw'); selected.tab = 'raw';"
     ng-class="{'active':selected.tab === 'raw'}">Raw data
  </button>
  <button class="btn"
     ng-click="selectView('summary'); selected.tab = 'summary';"  
     ng-class="{'active':selected.tab === 'summary'}">Summary
  </button>

  <button class="btn" ng-repeat="(key, value) in views"
          ng-click="selectView(key); selected.tab = key;"
          ng-class="{'active':selected.tab === key}">
    {{ key }}
  </button>
</div>

For more information, see What are the nuances of scope prototypal / prototypical inheritance in AngularJS?

Upvotes: 2

Lex
Lex

Reputation: 7194

Remember that ng-repeat creates its own local scope so any variables you reference there that are not defined on the parent scope will be created locally. Although you can put multiple commands in ng-click it is discouraged - it also seems that doing so will not cause a digest cycle for those items inside the ng-repeat.

You can resolve all of this by making selectedTab a property on your controller and having the selectView method set the value of selectedTab. Here's a quick example:

angular.module('app', [])
  .controller('ctrl', ($scope) => {
    $scope.selectedTab = 'raw';
    $scope.views = {
      Detail1: 'details',
      Detail2: 'details',
      Detail3: 'details'
      };
      
      $scope.selectView = function(view) {
        $scope.selectedTab = view;
      }
  });
.active {
  color: red !important;
}
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/3.3.7/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.7.2/angular.min.js"></script>
<div ng-app="app" ng-controller="ctrl">
  <div class="btn-group" 
       role="group" 
       aria-label="Basic example">
    <button class="btn" 
            ng-click="selectView('raw')" 
            ng-class="{'active':selectedTab === 'raw'}">Raw data</button>
    <button class="btn" 
            ng-click="selectView('summary')" 
            ng-class="{'active':selectedTab === 'summary'}">Summary</button>

    <button class="btn" 
            ng-repeat="(key, value) in views" 
            ng-click="selectView(key)" 
            ng-class="{'active':selectedTab === key}">
      {{ key }}
    </button>
  </div>
</div>

Upvotes: 5

Related Questions