AngularJS:在ng-repeat生成的作用域中设置变量

17

如何访问由ng-repeat生成的作用域集?

我想在这个问题的核心是,我不太明白a)传递到ng-repeat指令中的对象集合和b)它生成的作用域集合之间的关系是如何运作的。我可以操作(a),而ng-repeat作用域会监视并捕捉它,但是如何在作用域本身(b)上设置变量呢?

我的用例是,我有一组使用ng-repeat重复的元素,每个元素都有一个编辑视图,可以使用ng-show/ng-hide切换;每个元素的状态都保存在局部作用域的变量中。我想能够触发特定元素上的ng-show,但是我希望从ng-repeat外部调用触发器,因此我需要访问局部作用域变量。

有人能指点我正确的方向吗(或者告诉我我是否在错误的轨道上)?

谢谢

更新:下面的链接非常有帮助,谢谢。最终我为每个重复的元素创建了一个指令,并使用该指令的链接函数将其作用域添加到根作用域的集合中。


在ng-repeat创建的所有作用域都继承自父作用域,因此您可以轻松地从子作用域访问父作用域元素,但是您不能从子作用域更改父作用域元素(对于原始类型也是如此)。请查看https://github.com/angular/angular.js/wiki/Understanding-Scopes。 - Chandermani
谢谢 - 我会看一下。我的问题不是我想从子作用域访问父作用域,而是相反的情况。 - Steve
请参见https://dev59.com/R2Yq5IYBdhLWcg3w-FXQ。 - noj
谢谢您。我之前确实阅读过那篇文章。但我的问题不是关于继承,而是相反的情况。我该如何从父类中访问子类的变量? - Steve
你可以查看 scope.$broadcast 来实现你想要的功能。 - Chandermani
Steve,我正好遇到了你描述的问题。在使用angular.element时,需要采用如此复杂的解决方案。你有找到更简洁和好的方法吗? - Semyon Vyskubov
3个回答

19

这里有一个非常简单的方法来做我认为你想做的事情(当我需要做类似的事情时,我就想出了这个方法):

我们知道每个重复的项目都有自己的作用域。如果我们能将此作用域传递给定义在父作用域中的方法,则我们将能够按照我们想要的方式对其进行操作或添加属性。原来可以通过将this作为参数传递来实现此目的:

示例

// collection on controller scope
$scope.myCollection = [
  { name: 'John', age: 25 },
  { name: 'Barry', age: 43 },
  { name: 'Kim', age: 26 },
  { name: 'Susan', age: 51 },
  { name: 'Fritz', age: 19 }
];



// template view
<ul>
  <li ng-repeat="person in myCollection">
    <span ng-class="{ bold : isBold }">{{ person.name }} is aged {{ person.age }} </span>
    <button class="btn btn-default btn-xs" ng-click="toggleBold(this)">toggle bold</button>
  </li>
</ul>
当我们按下“切换粗体”按钮时,我们正在调用需要在控制器的$scope上定义的$ scope.toggleBold()方法。请注意,我们将this作为参数传递,实际上它是当前ng-repeat scope对象。
因此,我们可以这样操作。
$scope.toggleBold = function(repeatScope) {
  if (repeatScope.isBold) {
    repeatScope.isBold = false;
  } else {
    repeatScope.isBold = true;
  }
};

这里是一个可行的例子:http://plnkr.co/edit/Vg9ipoEP6wxG8M1kpiW3?p=preview


4
酷!我想知道为什么AngularJS官方网站上没有关于ng-repeat作用域中“this”的信息。 - Tsuneo Yoshioka

11

Ben Nadel提供了一个相当干净的解决方案,来解决"如何分配给ngRepeat$scope"问题,我在自己的项目中刚刚实现了这个方案。基本上,你可以在ngRepeat旁边添加一个ngController指令,并在控制器内操作ngRepeat$scope

下面是我自己构想的示例,演示了在控制器中分配给ngRepeat$scope。是的,有更好的方法来完成这个确切的事情。请参见Ben Nadel的帖子以获取更好的示例。

<div ng-controller="ListCtrl">
  <h1>ngRepeat + ngController</h1>
  <ul>
    <li ng-repeat="item in items" ng-controller="ItemCtrl" ng-show="isVisible">
      {{item.name}}
      <button ng-click="hide()">hide me!</button>
    </li>
  </ul>
</div>

<script type="text/javascript">
  var app = angular.module("myApp", []);

  app.controller("ListCtrl", function($scope) {
    $scope.items = [
      {name: "Item 1"},
      {name: "Item 2"},
      {name: "Item 3"}
    ];
  });

  app.controller("ItemCtrl", function($scope) {
    $scope.isVisible = true;
    $scope.hide = function() {
      $scope.isVisible = false;
    };
  });
</script>

编辑:我重新阅读了您的问题,看到您需要在父作用域中操作一堆子作用域,我认为您的指令方法是可行的。我仍然认为这个答案可能对一些人有用,因为我在寻找这个答案时遇到了您的问题。


1
当在作用域层次结构中工作时,使用$emit和$broadcast分派事件非常有用。 $emit向上分派事件,因此您的子作用域可以通知父作用域特定事件。 $broadcast则相反。
另外,由于子作用域可以访问父作用域属性,因此可以使用$watch在父作用域的特定属性上触发更改。
更新:关于访问子作用域,这可能对您有用:Get to get all child scopes in Angularjs given the parent scope

问题在于,父级作用域只与ng-repeat集合中的一个特定子级作用域进行通信...所以不确定如何使用$broadcast?对我来说最简单的解决方案就是直接在子级作用域上设置一个变量,这样它就会执行某些操作...有点像$scope.ngRepeatScopesCollection[index].var = y但是没有这样的集合吗?还是我在问愚蠢的问题/太菜了,无法理解angular的方式?;-) - Steve
在这种情况下,您可以将ng-repeat元素设置为可见,具体取决于注入到子作用域中的单个对象的特定属性。例如,如果对象的属性x等于true,则可以将元素设置为可见。请参考此链接:[http://docs.angularjs.org/api/ng.directive:ngClass] - Joe Minichino
那么在这种情况下,我认为你需要查看这个链接:[https://dev59.com/v2cs5IYBdhLWcg3wrmDC] - Joe Minichino
我使用了这些信息来解决问题,非常感谢你的指导!如果你想把链接作为答案发布,可以随意 - 我会接受并评论我实际做了什么。 - Steve
是的,可以说不如继承 $scope 那么干净,但仍然是一个相当合适的解决方案。这样可以避免我使用 this.$parent.$parent.$parent.$parent 来调用一个 init 方法 XD。 - Volte
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接