处理ng重复中的重复元素



我正在构建一个具有"播放列表"功能的应用程序。这是用ng-repeat = "element in playlist" 表示的ng个重复的自定义指令

因为我想允许用户在播放列表中重复使用同一元素两次,所以我尝试使用track by $index添加。

现在,令人困惑的是:当我从播放列表中删除一个元素时(我有一个函数removeElement(index),它本质上包含这样的东西:

$scope.removeElement = function(index){
  $scope.playlist.splice(index, 1);
}

发生了一些奇怪的事情:元素被正确地从$scope.playlist中删除,但由于某种原因,视图没有正确更新。最后一个元素似乎已删除。

此外,我也无法正确地重新排列数组中的元素。

当我删除track by $index时,这个问题消失了,所以我认为这是因为当你从数组中删除一个项时,如果你只看索引,那么看起来你刚刚删除了最后一个。

不过,这种行为很奇怪,因为被屏蔽的内容被正确地删除了——请参阅这个plunker

编辑:以上链接已被修改,以更好地显示问题,并显示我确定的答案。

这个问题也经过了轻微的编辑,让我更清楚地了解了我的意思。KayakDave下面的答案仍然是正确的,但更适合一系列原语(这是我最初的plunker的特色)。

TL;DR:如何在不牺牲控制其位置或正确删除元素的能力的情况下,将重复元素放入ng-repeat中?

使用track by的一大性能优势是Angular不会接触任何跟踪表达式未更改的DOM元素。这对于长ng-repeat列表来说是一个巨大的性能改进,也是添加track by的原因之一。

这种性能优化是您所看到的结果的根源。

当您在track by中使用$index时,您告诉ng-repeatng-repeat的第一次运行中将它创建的每个DOM元素绑定到它的位置($index)。

因此,颜色样式为红色的元素标记为0、橙色1、黄色2。。。最后是靛蓝5。

当你删除一个颜色时,Angular会查看你让它跟踪的索引,并发现你有一个更长的索引#5(因为你的列表比以前短了一个)。因此,它删除了标记为5的DOM元素,该元素的颜色样式为"靛蓝"。您仍然有一个索引#2,所以颜色为黄色的元素会保留下来。

令人困惑的是,由于数据绑定,DOM元素内的文本确实会更新。因此,当您删除"黄色"时,颜色为黄色的DOM元素将获得文本"绿色"。

简而言之,您看到的是ng-repeat保持黄色样式的DOM元素不变,因为它的跟踪值(2)仍然存在,但数据绑定已经更新了该元素内的文本

为了添加多个具有相同颜色的条目,您需要为用于track by的每个条目添加一个唯一的标识符。一种方法是对每个条目使用键值对,其中键是您的唯一标识符。像这样:

$scope.colorlist = {1:'red', 2:'orange',3:'yellow',4:'green',5:'blue',6:'indigo',7:'yellow'};

然后track by密钥如下:

<color-block ng-repeat="(key, color) in colorlist track by key" color="{{color}}" ng-transclude>
    {{color}}
</color-block>

确保使用该键进行删除选择:

<option value="{{key}}" ng-repeat="(key,color) in colorlist">{{color}}</option>

现在,颜色样式为黄色的DOM元素被绑定到您为"黄色"数组元素指定的键上。因此,当您删除"黄色"时,ng-repeat将删除正确的DOM元素,一切正常。

你可以在这里看到它的工作原理:http://plnkr.co/edit/cFaU8WIjliRjPI6LInZ0?p=preview

我想为这个问题添加另一个答案,因为我发现了一个更简单的解决方案。

文档中有一个关于ng-repeat的重要部分很容易遗漏,特别是关于重复数据错误的部分。

它指出:

默认情况下,集合通过引用进行键控

读过这篇文章后,解决方案是显而易见的——因为我不是在处理基元(是的,plunker是,但这是一个过度简化),我需要复制复制的对象并将其副本添加到数组中。这意味着当按$index删除track并让默认行为接管时,一切都能正常工作。

Angular使这变得特别容易,因为jqlite有一个.copy。方法

以下是我所说的在plunker中演示的内容

最新更新