AngularJS: ng-repeat and scoped ng-click

Issue

I have a series of list items populated by ng-repeat. Visibility is controlled by a simple ng-click and ng-show relationship. For the most part, this works just fine, but I want to be able to control the show/hide behavior with a global button that will show or hide all available items on the list.

Fair disclosure: I’m still very new to AngularJS. I’m aware that this is a scoping issue, but I’m not sure how to solve it. This is almost certainly a case of not knowing the right question to ask.

I have a jsfiddle here demonstrating my difficulty: http://jsfiddle.net/36BYs/838/

Sample HTML:

<div ng-controller="MainCtrl">

  <span ng-show="!IsVisible" ng-click="isVisible = !isVisible;" >
    (show/hide all)
    <i class="fa fa-minus-square-o fa-small"></i>
  </span>
<ul>
        <li ng-repeat="mentor in mentors">
        <a ng-click="isVisible = !isVisible;">show/hide</a>
        <span ng-show="isVisible">{{mentor}}</span>
        </li>
    </ul>
</div>

Sample JS:

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

function MainCtrl( $scope ) {
  $scope.isVisible = true;
  $scope.mentors = [ 'Jonathan', 'Nathan', 'Chris', 'Brian', 'Timothy' ];
}

It works fine as long as you have not independently toggled one of the list items. but If you click to show/hide on a particular line, the global ng-click loses control of the item.

Thanks in advance for any advice you can offer.

Solution

While other comments have been useful, user miqid’s comment provided the best answer to my specific need:

As you’re aware, ng-repeat introduces a separate scope so that each isVisible underneath no longer tracks the parent isVisible. One solution is to explicitly track isVisible per item in addition to tracking a parent visibility state that overrides item-level one if necessary. Demo—jsfiddle.net/uLykhg0z – miqid 14 hours ago

The jsfiddle is a variation on Andrew Shepherd’s solution (jsfiddle.net/uLykhg0z):

HTML:

<div ng-controller="MainCtrl">

  <span ng-show="!IsVisible" class = "clickable" ng-click="toggleVisibility()" >
    (show/hide all)
    <i class="fa fa-minus-square-o fa-small"></i>
  </span>
  <ul>
        <li ng-repeat="mentor in mentors">
        <a class = "clickable" ng-click="mentor.isVisible = !mentor.isVisible;">show/hide</a>
        <span ng-show="mentor.isVisible">{{mentor.name}}</span>
        </li>
    </ul>
</div>

JS:

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

function MainCtrl( $scope ) {
    var isVisible = true;
  $scope.mentors = [
    { name: 'Jonathan', isVisible: true },
    { name: 'Nathan', isVisible: true },
    { name: 'Chris', isVisible: true },
    { name: 'Brian', isVisible: true },
    { name: 'Timothy', isVisible: true },
  ];
  $scope.toggleVisibility = function () {
    isVisible = !isVisible;
    $scope.mentors = $scope.mentors.map(function (mentor) {
        mentor.isVisible = isVisible;
      return mentor;
    });
  };
}

This allowed me to accommodate some more complex nesting that I have to deal with in a tree structure.

Thanks again for all of your help, folks!

Answered By – e-barnett

Answer Checked By – Senaida (AngularFixing Volunteer)

Leave a Reply

Your email address will not be published.