如何设置布尔标志以使用ng-repeat折叠/展开行

时间:2014-10-04 04:18:44

标签: angularjs angularjs-ng-repeat

我有this plunker代码。

我尝试做的是每行显示一次灰色框。

为了达到这个目的,我想修改partition过滤器,以便返回一个JSON,按行添加一个新属性,以了解是否扩展了灰色框。

但是,我无法成功返回JSON。

您知道如何修改过滤器以返回JSON或更好的方式来逐行显示灰色框吗?

相关问题:

更新1

通过在不修改过滤器的情况下使用行的ng-repeat的正确范围,可以很容易地解决问题,这要归功于@ m59。

http://plnkr.co/edit/eEMfI1lv6z1MlG7sND6g?p=preview

更新2

Live Demo

如果我尝试修改item,则会再次调用ng-repeat而失去props值。

  <div ng-repeat="friendRow in friends | partition:2" 
       ng-init="props = {}">
    <div ng-repeat="item in friendRow" 
         ng-click="collapse(item)" 
         ng-class="{myArrow: showArrow}">
      {{item.name}} {{item.age}} years old.
      <div>{{item.name}}</div>
    </div>
    <div collapse="!props.isExpanded">
      some content
      <br/>
      <input type="text" ng-model="currentItem.name">
    </div>
  </div>

JS

  $scope.collapse = function(item){
     this.props.isExpanded  = !this.props.isExpanded;
     this.showArrow = !this.showArrow;
     $scope.currentItem = item;
  };

这会导致每次修改item时灰色框都会折叠。任何线索?

1 个答案:

答案 0 :(得分:3)

我已更新my code/answer regarding partitioning data。在决定项目方法之前,充分理解所有这些是非常重要的。

您在plnkr演示中遇到的问题是,您正在修改父级$scope,而不是该行的ng-repeat的scope

只需在行上设置一个标志,并在点击时切换它:

Live Demo

<div 
  class="row" 
  ng-repeat="friendRow in friends | partition:2"
  ng-init="isExpanded = false" 
  ng-click="isExpanded = !isExpanded"
>
  <div ng-repeat="item in friendRow">
    {{item.name}} {{item.age}} years old.  
  </div>
  <div collapse="!isExpanded">
    some content
  </div>
</div>

要在控制器中的某个功能中访问正确的scope,您可以使用this关键字代替$scopethis将引用调用函数的作用域,而$scope引用带有ng-controller的元素附加的作用域(您想要的ng-repeat作用域的父作用域靶)。

<div 
  class="row" 
  ng-repeat="friendRow in friends | partition:2" 
  ng-click="collapse()"
>

JS:

$scope.collapse = function() {
   this.isExpanded  = !this.isExpanded;
};

如果你想在ng-click元素上保留item指令而不是像我一样把它放在row元素上,那么你要处理另一个子范围,因为那个内在的ng-repeat。因此,您需要遵循“点”规则,以便子范围可以更新collapse指令所在的父范围。这意味着您需要在对象中嵌套isExpanded。在此示例中,我使用ng-init="props = {}",然后使用props.isExpanded。点规则有效,因为子节点共享对props的相同对象引用,因此属性是共享的而不是仅仅复制,就像在普通的JavaScript对象引用中一样。

Live Demo

<div 
  class="row"
  ng-repeat="friendRow in friends | partition:2" 
  ng-init="props = {}"
>
  <div ng-repeat="item in friendRow" ng-click="collapse()">
    {{item.name}} {{item.age}} years old.
  </div>
  <div collapse="!props.isExpanded">
    some content
  </div>
</div>

JS:

$scope.collapse = function(){
   this.props.isExpanded  = !this.props.isExpanded;
};

更新

我们一直在处理越来越多的项目问题。你真的只需要进行实验/研究并理解在更深层次上发生的一切,或者只是一个接一个的问题。我会尽最大努力让你走上正轨,但你需要尝试基本概念并从那里开始。

通过props放置$scope.expandedStates然后将当前ng-repeat的$index传递给您的函数来解决expandedStates重新初始化的问题。只在视图中使用它并设置$scope.expandedStates[$index] = !$scope.expandedStates[$index]的属性,如ng-repeat。使用嵌套的$parent.$index,您需要执行this,以便将状态与行而不是项目相关联。

但是,您将遇到过滤器的另一个问题:使用旧的分区代码,每次键入字符时,分区内的输入都将失去焦点。使用新代码,视图会更新,但基础模型不会更新。您可以使用this answer中的分区过滤器来解决此问题,但根据我对该代码的理解,它可能会有一些意外的行为,并且还需要将$scope.partitionedFriends = partitionFilter($scope.friends, 2); $scope.$watch('partitionedFriends', function(val) { $scope.friends = [].concat.apply([], val); }, true); // deep watch 作为参数传递给过滤器。我不建议你这样做。

过滤器意味着幂等,因此通过某种记忆来稳定它们在技术上是一种黑客攻击。有些人认为你根本不应该这样做,但我认为这很好。但是,当你出于显示目的而不是用户输入时,你肯定应该这样做!因为您在分区视图中接受用户输入,所以我建议在控制器中对数据进行分区,然后将其与手表(连续)或需要提交时一起重新连接。

{{1}}