98

I am trying to work how to add a class with ngClick. I have uploaded up my code onto plunker Click here. Looking at the angular documentation i can't figure out the exact way it should be done. Below is a snippet of my code. Can someone guide me in the right direction

 <div ng-show="isVisible" ng-class="{'selected': $index==selectedIndex}" class="block"></div>

Controller

var app = angular.module("MyApp", []);
app.controller("subNavController", function ($scope){

        $scope.toggle = function (){
            $scope.isVisible = ! $scope.isVisible;
        };

        $scope.isVisible = false;
    });
1
  • not clear from demo or explnation what objective is. Seem to be trying to toggle a menu, but why aare you only toggling menu link in demo? Commented Dec 8, 2013 at 23:14

10 Answers 10

144

I want to add or remove "active" class in my code dynamically on ng-click, here what I have done.

<ul ng-init="selectedTab = 'users'">
   <li ng-class="{'active':selectedTab === 'users'}" ng-click="selectedTab = 'users'"><a href="#users" >Users</a></li>
   <li ng-class="{'active':selectedTab === 'items'}" ng-click="selectedTab = 'items'"><a href="#items" >Items</a></li>
</ul>
Sign up to request clarification or add additional context in comments.

9 Comments

-1 for ng-init. According to AngularJS docs - The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
I just avoiding the controller part "here", as this is just for showing the basic functionality of how to do that...
You can also use the undocumented syntax of ` ng-class="{'active': true}[selectedTab === 'users']"`
I don't understand why this would work. I'm doing something very similar in Angular 1.3.8 and the conditional class is not removed from an element when another is clicked. I would assume because the other elements are not re-rendered. Why then, did this ever work? Did old versions of Angular re-build the entire list when a single element was clicked?
I'm just adding this because it may help someone else down the line. angular-ui-router has the functionality you are specifying and much more. You create states which are represented by a uri. Each state may have 1 or more controllers, 1 or more templates, and 1 or more views bound to them. Links are generated using the ui-sref directive. The ui-sref-active directive will bind a specific class to that element when the state is active. Angular UI-Router Documentation
|
110

You just need to bind a variable into the directive "ng-class" and change it from the controller. Here is an example of how to do this:

var app = angular.module("ap",[]);

app.controller("con",function($scope){
  $scope.class = "red";
  $scope.changeClass = function(){
    if ($scope.class === "red")
      $scope.class = "blue";
    else
      $scope.class = "red";
  };
});
.red{
  color:red;
}

.blue{
  color:blue;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<body ng-app="ap" ng-controller="con">
  <div ng-class="class">{{class}}</div>
  <button ng-click="changeClass()">Change Class</button>    
</body>

Here is the example working on jsFiddle

4 Comments

class is a reserved word, use className instead, YUI compiler will fail to minify this.
What about if I want use this code for more than one div in the same view? this code actuali change class for all div, how I can apply class only to the selected clicked item
Thanks. To fully understand what is happening when the change Class button is clicked open the console and view the code.
Have a look at this SO thread also. Might not be 100% linked with the question scope but still provides extra useful information: stackoverflow.com/questions/31047094/…
12

There is a simple and clean way of doing this with only directives.

<div ng-class="{'class-name': clicked}" ng-click="clicked = !clicked"></div>

Comments

9

you can also do that in a directive, if you want to remove the previous class and add a new class

    .directive('toggleClass', function() {
    return {
        restrict: 'A',
        link: function(scope, element, attrs) {
            element.bind('click', function() {
                if(element.attr("class") == "glyphicon glyphicon-pencil") {
                    element.removeClass("glyphicon glyphicon-pencil");
                    element.addClass(attrs.toggleClass);
                } else {
                    element.removeClass("glyphicon glyphicon-ok");
                    element.addClass("glyphicon glyphicon-pencil");
                }
            });
        }
    };
});

and in your template:

<i class="glyphicon glyphicon-pencil" toggle-class="glyphicon glyphicon-ok"></i>

4 Comments

why do you have the names of the icons in the tag and the directive?
That's a dumb comment. It's a perfectly legit thing to do although I agree that it's perhaps not the place for it when you're explaining how to do something in Angular
why wouldn't you just do: angular.element('glyphicon glyphicon-pencil).removeClass('glyphicon glyphicon-pencil')? angular.element is pretty much angular's jqLite version of $ in jquery. You could just create a service or directive that calls this function and pass in removedClasses and addedClasses in the constructor
That's true, but I was trying to use plain angular js.
7

You have it exactly right, all you have to do is set selectedIndex in your ng-click.

ng-click="selectedIndex = 1"

Here is how I implemented a set of buttons that change the ng-view, and highlights the button of the currently selected view.

<div id="sidebar" ng-init="partial = 'main'">
    <div class="routeBtn" ng-class="{selected:partial=='main'}" ng-click="router('main')"><span>Main</span></div>
    <div class="routeBtn" ng-class="{selected:partial=='view1'}" ng-click="router('view1')"><span>Resume</span></div>
    <div class="routeBtn" ng-class="{selected:partial=='view2'}" ng-click="router('view2')"><span>Code</span></div>
    <div class="routeBtn" ng-class="{selected:partial=='view3'}" ng-click="router('view3')"><span>Game</span></div>
  </div>

and this in my controller.

$scope.router = function(endpoint) {
    $location.path("/" + ($scope.partial = endpoint));
};

Comments

4

var app = angular.module("MyApp", []);
app.controller("subNavController", function ($scope){

        $scope.toggle = function (){
            $scope.isVisible = ! $scope.isVisible;
        };

        $scope.isVisible = false;
    });
<div ng-show="isVisible" ng-class="{'active':isVisible}" class="block"></div>

Comments

3

I used Zack Argyle's suggestion above to get this, which I find very elegant:

CSS:

.active {
    background-position: 0 -46px !important;
}

HTML:

<button ng-click="satisfaction = 'VeryHappy'" ng-class="{active:satisfaction == 'VeryHappy'}">
    <img src="images/VeryHappy.png" style="height:24px;" />
</button>
<button ng-click="satisfaction = 'Happy'" ng-class="{active:satisfaction == 'Happy'}">
    <img src="images/Happy.png" style="height:24px;" />
</button>
<button ng-click="satisfaction = 'Indifferent'" ng-class="{active:satisfaction == 'Indifferent'}">
    <img src="images/Indifferent.png" style="height:24px;" />
</button>
<button ng-click="satisfaction = 'Unhappy'" ng-class="{active:satisfaction == 'Unhappy'}">
    <img src="images/Unhappy.png" style="height:24px;" />
</button>
<button ng-click="satisfaction = 'VeryUnhappy'" ng-class="{active:satisfaction == 'VeryUnhappy'}">
    <img src="images/VeryUnhappy.png" style="height:24px;" />
</button>

Comments

2

If you prefer separation of concerns such that logic for adding and removing classes happens on the controller, you can do this

controller

 (function() {
    angular.module('MyApp', []).controller('MyController', MyController);

    function MyController() {
      var vm = this;
      vm.tab = 0;

      vm.setTab = function(val) {
          vm.tab = val;
       };
      vm.toggleClass = function(val) {
          return val === vm.tab;
           };
        }
    })();

HTML

<div ng-app="MyApp">
  <ul class="" ng-controller="MyController as myCtrl">
    <li ng-click="myCtrl.setTab(0)" ng-class="{'highlighted':myCtrl.toggleClass(0)}">One</li>
    <li ng-click="myCtrl.setTab(1)" ng-class="{'highlighted':myCtrl.toggleClass(1)}">Two</li>
    <li ng-click="myCtrl.setTab(2)" ng-class="{'highlighted':myCtrl.toggleClass(2)}">Three</li>
   <li ng-click="myCtrl.setTab(3)" ng-class="{'highlighted':myCtrl.toggleClass(3)}">Four</li>
 </ul>

CSS

.highlighted {
   background-color: green;
   color: white;
}

Comments

0

I can't believe how complex everyone is making this. This is actually very simple. Just paste this into your html (no directive./controller changes required - "bg-info" is a bootstrap class):

<div class="form-group col-md-12">
    <div ng-class="{'bg-info':     (!transport_type)}"    ng-click="transport_type=false">CARS</div>
    <div ng-class="{'bg-info': transport_type=='TRAINS'}" ng-click="transport_type='TRAINS'">TRAINS</div>
    <div ng-class="{'bg-info': transport_type=='PLANES'}" ng-click="transport_type='PLANES'">PLANES</div>
</div>

Comments

-1

for Reactive forms -

HTML file

<div class="col-sm-2">
  <button type="button"  [class]= "btn_class"  id="b1" (click)="changeMe()">{{ btn_label }}</button>
</div>

TS file

changeMe() {
  switch (this.btn_label) {
    case 'Yes ': this.btn_label = 'Custom' ;
    this.btn_class = 'btn btn-danger btn-lg btn-block';
    break;
    case 'Custom': this.btn_label = ' No ' ;
    this.btn_class = 'btn btn-success btn-lg btn-block';
    break;
    case ' No ': this.btn_label = 'Yes ';
      this.btn_class = 'btn btn-primary btn-lg btn-block';
      break;
  }

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.