Nyxynyx
Nyxynyx

Reputation: 63647

ng-click function affecting all ng-repeat elements

A series of links apple, orange, banana are created using ng-repeat. Clicking on these links will cause that fruit's color to appear below the link.

Problem: However when any link is clicked, the colors for all the fruits are shown. How can we restrict the click event to only show the color of the fruit that is clicked?

Jsfiddle: http://jsfiddle.net/hut13fox/

HTML

<div ng-controller="FruitCtrl">
    <div ng-repeat="f in fruits">
        <a href="#" ng-click="toggleShow()">{{ f.title }}</a>
        <div ng-show="show">
            {{ f.color }}
        </div>
    </div>
</div>

JS

var myApp = angular.module('myApp', []);

FruitCtrl = function($scope) {
    $scope.fruits = [
        { title: 'apple', color: 'red' },
        { title: 'orange', color: 'orange' },
        { title: 'banana', color: 'yellow' }
        ];

    $scope.show = false
    $scope.toggleShow = toggleShow

    function toggleShow() {
        console.log('toggle')
        $scope.show = !$scope.show
    }
}
console.log('Hello')

Upvotes: 6

Views: 523

Answers (3)

Michael Kang
Michael Kang

Reputation: 52847

I would do this which doesn't require you to modify your model:

<div ng-controller="FruitCtrl">
  <div ng-repeat='f in fruits'>
        <a href="#" ng-click='show=!show'>{{ f.title }}</a>
        <div ng-show='show'>
            {{ f.color }}
        </div>
  </div>
</div>

The reason this works is because an ngRepeat will create a child scope with each iteration. By using the expression show=!show, it ensures that the expression is evaluated against the current iteration's child scope, and each child scope gets its own "show" scope property.

Upvotes: 3

Shashank Agrawal
Shashank Agrawal

Reputation: 25797

Change your code something like this:

<div ng-controller="FruitCtrl">
  <div ng-repeat="f in fruits">
        <a href="#" ng-click="toggleShow(f)">{{ f.title }}</a>
        <div ng-show="f.show">
            {{ f.color }}
        </div>
  </div>
</div>

And your JS to

function toggleShow(f) {
    console.log('toggle')
    f.show = !f.show
}

Basically, you were previously using a common scope show for all items which was causing the problem. And now we are using each fruit items separately to toggle each item using f.show by maintaining a key show in your each fruit item.

See a working code here:

var myApp = angular.module('myApp', []);

FruitCtrl = function($scope) {
  $scope.fruits = [{
    title: 'apple',
    color: 'red'
  }, {
    title: 'orange',
    color: 'orange'
  }, {
    title: 'banana',
    color: 'yellow'
  }];

  $scope.show = false
  $scope.toggleShow = toggleShow

  function toggleShow(f) {
    console.log('toggle')
    f.show = !f.show
  }
}

myApp.controller('FruitCtrl', FruitCtrl);

console.log('Hello')
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="myApp">
  <div ng-controller="FruitCtrl">
    <div ng-repeat='f in fruits'>
      <a href="#" ng-click='toggleShow(f)'>{{ f.title }}</a>
      <div ng-show='f.show'>
        {{ f.color }}
      </div>
    </div>
  </div>

</div>

Upvotes: 1

Lucas Rodriguez
Lucas Rodriguez

Reputation: 1203

You should set the visibility in each element

<div ng-controller="FruitCtrl">
 <div ng-repeat='fruit in fruits'>
       <a href="#" ng-click='toggleShow(fruit)'>{{ fruit.title }}</a>
       <div ng-show='fruit.show'>
           {{ fruit.color }}
       </div>
 </div>
</div>

And format your JS like

function toggleShow(fruit) {
    fruit.show = fruit.show
}

Your object will be something like:

   $scope.fruits = [
    { title: 'apple', color: 'red', show : true },
    { title: 'orange', color: 'orange', show : true },
    { title: 'banana', color: 'yellow', show : true }
    ];

This way you can control the defaults

Also, you don't necessarily need the toggle method, you can do it inline in the html tag:

<a href="#" ng-click='fruit.show = !fruit.show'>{{ fruit.title }}</a>

Upvotes: 3

Related Questions