Adding class to an element on its click event
Asked Answered
P

4

7

I am new to Angular Js. I need to add a class to an element on its click event. I tried the following code. But it is not working.

<html>
<head>
    <style>
        .active{color:red;}
    </style>

    <script src="js/lib/jquery.min.js"></script>
    <script src="js/lib/angular.min.js"></script>
</head>
<body ng-app="MyApp" ng-controller="MyController">

    <div ng-repeat="data in datas">
        <p ng-click='selectMe()'>{{data.name}}</p>
    </div>

    <script>
    var app = angular.module('MyApp',[]);
    app.controller('MyController',function($scope){
         $scope.datas = [{name:"first"},{name:"second"}];

         $scope.selectMe = function (){
            $(this).addClass('active');
         }
    });

    </script>
</body>
</html>

What is the problem in this code? Is it necessary to use ng-class ? How to do it?

Poniard answered 21/10, 2013 at 11:52 Comment(3)
don't manipulate with DOM in controller, use directiveMis
I am not familiar with using angular js. Can you please help me to do this with directivePoniard
I agree with Maxim. Additionally this in the ng-click is not the element (as in jQuery) but the scope. Perhaps you can access the element through the $event object as: ng-click="selectMe($event)" and in the controller: $scope.selectMe = function($event).Bowens
S
36

You can pass $event to click

<p ng-click='selectMe($event)'>{{data.name}}</p>

//code:
$scope.selectMe = function (event){
   $(event.target).addClass('active');
}
Supportive answered 21/10, 2013 at 12:0 Comment(2)
I tried the second one. It is working. But the problem is all the elements are changing into active class.Poniard
Can i use angular.element(event.target).addClass('active');Unready
B
7

The Angular way (MVVM actually) to do this is to update the model through the click event and then paint according to the model, e.g.:

app.controller('MyController',function($scope){
    $scope.datas = [{name:"first", selected:false},{name:"second",selected:false}];
    $scope.selectMe = function(data) {
        var i;
        for( i=0; i < $scope.datas.length; i++ ) {
            $scope.datas[i].selected = false;
        }
        data.selected = true;
    };
}

And the HTML:

<div ng-repeat="data in datas">
    <p ng-click='selectMe(data)' ng-class="{selected: data.selected}>{{data.name}}</p>
</div>
Bowens answered 21/10, 2013 at 12:3 Comment(0)
U
6

I know this question already has an answer, but I was shocked when I realized that the chosen best answer (which I had already implemented in some of my code) doesn't align with the AngularJS documentation.

According to AngularJS Documentation:

Do not use controllers to:

  • Manipulate DOM — Controllers should contain only business logic. Putting any presentation logic into Controllers significantly affects its testability. Angular has databinding for most cases and directives to encapsulate manual DOM manipulation.

huston007's answer works great, however, it does not follow this recommendation.

With this as your data input:

$scope.peeps = {
  '0': {
    'id': 0,
    'first_name': 'Tony',
    'last_name': 'Martin'
  },
  '1': {
    'id': 1,
    'first_name': 'Gerald',
    'last_name': 'Johanssen'
  },
  '2': {
    'id': 2,
    'first_name': 'Bobby',
    'last_name': 'Talksalot'
  }
};

And this your html:

<ul>
  <li ng-repeat="peep in peeps" 
      ng-click="addOrRemoveClassFromMe(peep.id)"
      ng-class="{selected: selectedPeeps[peep.id]}">
     {{peep.first_name}} {{peep.last_name}}
  </li>
</ul>

My suggested solution uses an array of objects with the person's id as the key and a booleon as the value. This is linked to in the DOM through the ngClass directive.

//-- create the selected peeps array
$scope.selectedPeeps = {};

//-- add the id to an array with a true-ey value
$scope.addOrRemoveClassFromMe = function(id) {

  //-- Set selected peeps as true/false
  if($scope.selectedPeeps[id]) {
    $scope.selectedPeeps[id] = false;
  } else {
    $scope.selectedPeeps[id] = true;
  }
};

You can check out my codepen here.

I also have another version that removes all of this logic from the controller, leaving only the variable definition, but I thought that might be out of the scope of this question. (codepen.io/joshwhatk/pen/bwmid)

Hope this helps.

Unloosen answered 4/6, 2014 at 14:58 Comment(1)
Solid! Great implementation.Flotow
B
4

I know this is an old question but just came across it and think there's a simpler answer to any of the ones given here:

<div ng-repeat="data in datas">
    <p ng-click="active=!active"
       ng-class="{'active': active}">{{data.name}}</p>
</div>

No code needed in the controller other than to create your datas array. This works because the active variable is created within the child scope of each div created by the ng-repeat rather than in the controller's scope.

I've created an updated version of @joshwhatk's codepen here

Billfish answered 29/2, 2016 at 10:47 Comment(1)
nice solve my problem, but if I have more <p> how can I remove the class and add? I mean remove from p and add to the next p clickedOncoming

© 2022 - 2024 — McMap. All rights reserved.