AngularJS: ng-repeat и scoped ng-click - PullRequest
       13

AngularJS: ng-repeat и scoped ng-click

0 голосов
/ 11 сентября 2018

У меня есть серия пунктов списка, заполненных ng-repeat. Видимость контролируется простыми отношениями ng-click и ng-show. По большей части, это работает просто отлично, но я хочу иметь возможность контролировать поведение «показать / скрыть» с помощью глобальной кнопки, которая будет отображать или скрывать все доступные элементы в списке.

Справедливое раскрытие: я все еще очень плохо знаком с AngularJS. Я знаю, что это ограниченная проблема, но я не уверен, как ее решить. Это почти наверняка случай незнания правильного вопроса.

У меня есть jsfiddle, демонстрирующий мою трудность: http://jsfiddle.net/36BYs/838/

Пример 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>

Образец JS:

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

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

Работает нормально, если вы не переключили один из элементов списка независимо друг от друга. но если вы щелкнете, чтобы показать / скрыть определенную строку, глобальный щелчок по нг теряет контроль над элементом.

Заранее благодарим за любой совет, который вы можете предложить.

Ответы [ 3 ]

0 голосов
/ 11 сентября 2018

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

app.controller("myCtrl", function ($scope) {
  $scope.mentors = [
    'Jonathan',
    'Nathan',
    'Chris',
    'Brian',
    'Timothy'
  ];
  
  $scope.showAll = function() {
    $scope.visibleMentors = $scope.mentors.slice();
  };
  
  $scope.hideAll = function() {
    $scope.visibleMentors = [];
  };
  
  $scope.isVisible = function(mentor) {
    return $scope.visibleMentors.includes(mentor);
  };
  
  $scope.show = function(mentor) {
    $scope.visibleMentors.push(mentor);
  };
  
  $scope.hide = function(mentor) {
    $scope.visibleMentors.splice($scope.visibleMentors.indexOf(mentor), 1);
  };
  
  $scope.showAll();
});
a {
  cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.0.8/angular.min.js"></script>

<div ng-app="myApp">
  <div ng-controller="myCtrl">
    <button ng-click="showAll()">show all</button>
    <button ng-click="hideAll()">hide all</button>                                                                                                                                                                           
    <ul>
      <li ng-repeat="mentor in mentors">
        <a ng-show="isVisible(mentor)" ng-click="hide(mentor)">hide</a>
        <a ng-show="!isVisible(mentor)" ng-click="show(mentor)">show</a>
        <span ng-show="isVisible(mentor)">
          {{mentor}}
        </span>
      </li>
    </ul>
  </div>
</div>
0 голосов
/ 11 сентября 2018

В то время как другие комментарии были полезны, комментарий пользователя miqid предоставил лучший ответ на мою конкретную потребность:

Как вы знаете, ng-repeat вводит отдельную область видимости, так что каждый элемент isVisible под ним больше не отслеживает родительский элемент isVisible. Одним из решений является явное отслеживание isVisible для каждого элемента в дополнение к отслеживанию родительского состояния видимости, которое переопределяет уровень элемента, если это необходимо. Демо—jsfiddle.net/uLykhg0z - miqid 14 часов назад

jsfiddle - это вариант решения Эндрю Шепарда (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;
    });
  };
}

Это позволило мне разместить несколько более сложных вложений, с которыми мне приходится иметь дело, в древовидной структуре.

Еще раз спасибо за вашу помощь, ребята!

0 голосов
/ 11 сентября 2018

Похоже, что на начальном рендере angular пытается оценить isVisible для каждого наставника. Поскольку mentor.isVisible будет undefined, угловая структура использует родительскую область видимости isVisible.

.

Но затем, когда вы переключаете одного конкретного наставника, вы фактически присваиваете логическое свойство isVisible этой конкретной строке mentor. (Потому что вы можете с радостью присоединить дополнительные свойства к string в javascript).

После этого вы можете переключать show/hide all, и это повлияет на каждого наставника, которому не было назначено собственное свойство isVisible.

Это демонстрирует, насколько запутанной была область видимости в начальной версии AngularJS.

Вот рабочий ответ: http://jsfiddle.net/fkw5923t/

Я внес некоторые изменения:

  • Вместо присвоения значений $scope я использую синтаксис controllerName as mnemonic. В коде контроллера я присваиваю значения this, а не $scope. Я предпочитаю такой подход, потому что теперь обзор ясен и ясен
  • Я изменил mentor со строки на объект, состоящий из двух значений: name и isVisible. Опять же, теперь это делает правила области видимости ясными и явными.

HTML:

<div ng-controller="MainCtrl as mainCtrl">

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

JavaScript:

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

function MainCtrl() {
  this.isVisible = true;
  var mentorNames = ['Jonathan', 'Nathan', 'Chris', 'Brian', 'Timothy'];
  this.mentors = mentorNames.map(
      name => { 
         return { 
             name:name, 
             isVisible:true 
         }; 
      }
  );
}
...