Sammy
Sammy

Reputation: 3099

Removing Class from all children except clicked child on ng-click in Angular

I have a simple list item being parsed with ng-repeat:

<ul>
    <li ng-repeat="item in items" class="commonClass" ng-class="{'on': on_var}" ng-click="on_var=!on_var"> 
   {{item.name}} 
    <li>
</ul>

clicking on a list-item will add the class name 'on' as expected. but I want to remove all other 'on' classes as soon as you click on another list-item and only add it to the one clicked. I come from a jQuery background and I am new to angular. All I want to do is something like this:

$("li.commanClass").click(function(){ 
    $("li.commonClass").removeClass('on');
    $(this).addClass('on');
})

I want to know what is the "angular way" of achieving this result

jsfiddle

Thanks.

Upvotes: 3

Views: 8643

Answers (4)

Hieu Tran AGI
Hieu Tran AGI

Reputation: 899

I think you should refer a directive for whole your project instead of controller.

<div class="nav-item">
    <ul>
        <li active-me="on">Item 1</li>
        <li active-me="on">Item 2</li>
        <li active-me="on">Item 3</li>
        <li active-me="on">Item 4</li>
        <li active-me="on">Item 5</li>
    </ul>
</div>

Then create activeMe directive:

angular.module('app').directive('activeMe', function(){
    return {
        restrict: 'A',
        scope: {
            activeMe: '@'
        },
        link: function(scope, element, attrs) {
            element.bind('click', function() {
                if (scope.activeMe !== undefined && scope.activeMe.trim().length > 0) {
                    element.parent().children().removeClass(scope.activeMe);
                    element.addClass(scope.activeMe);
                } else {
                    element.parent().children().removeClass('active');
                    element.addClass('active');
                }
            });
        }
    };
});

Upvotes: 0

charlietfl
charlietfl

Reputation: 171669

In angular you want to pass object references to child scopes as much as possible. This way you can use prototypical object inheritance that can branch down many levels.

Think of a scope as being a model. In the case of ng-repeat it creates a child scope for each element. So if the parent scope holds a model it will be passed as reference to the child scopes. Each of these child scopes will hold a reference to the parent scope model object.

Thus you can do:

<li ng-repeat="item in model.items" 
    ng-class="{'on': model.selected==item}" 
    ng-click="model.selected=item">{{ item.name }}</li> 

Then in controller:

$scope.model = {
        selected: null,
        items = [
            {name: "Apple"}, 
            {name: "Banana"}, 
            {name: "California"}
         ]
    };

Try to avoid using functions as above answer does. These functions will get called many times and will add unnecessary extra overhead.

Valuable post to read: "Thinking in AngularJS" if I have a jQuery background?

DEMO

Upvotes: 6

chubbsondubs
chubbsondubs

Reputation: 38716

Fiddle coming at ya of jsparks answer:

http://jsfiddle.net/eHDTF/

See fiddle for code!

Upvotes: 1

jsparks
jsparks

Reputation: 1030

You can add a variable to your scope to maintain which item is selected, and a function on your scope that toggles the variable.

Controller:

app.controller('myCtrl', function($scope) {
    $scope.items = 
    [
        {name: "Apple"},
        {name: "Banana"},
        {name: "California"}
    ]

    $scope.selectItem = function( item ) {
        $scope.selectedItem = item;
    };
})

HTML:

<div ng-app="myApp">
    <ul ng-controller="myCtrl">
        <li ng-repeat="item in items" class="commonClass" ng-class="{'on': selectedItem === item}" ng-click="selectItem(item)">
            {{ item.name }}
        </li>
    </ul>
</div>

Upvotes: 2

Related Questions