2013-11-28 76 views
6

我正在构建一个具有“播放列表”特征的应用程序。这是一个ng重复的自定义指令ng-repeat = "element in playlist"处理ng-repeat中的重复元素

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

现在,有什么困惑的是:当我从播放列表中删除一个元素(我有一个功能removeElement(index)基本上包含了这样的事情:

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

奇怪的事情发生了:从正确删除的元素$scope.playlist,但由于某些原因的看法并不正确更新。最后一个元素似乎被删除。

而且,我无法正确地重新排序数组中的元素无论是。

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

的行为是奇怪,但因为transcluded内容被删除正确 - see this plunker

编辑:上面的链接已被修改,以更好地说明问题,也表明我看中了答案。

这个问题也经过了微小的修改,使得它更清晰。下面的KayakDave的答案仍然是正确的,但更适合于一系列基元(我的原始蹦极功能)。

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

回答

5

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

有一个重要的section of the documentationng-repeat这是很容易错过,特别是在dupes错误。

它指出:

默认情况下,集合引用

键看完这个,该解决方案是显而易见的 - 因为我不是用原语处理(是的,plunker是,但这是一个过于简化)我需要复制重复的对象,并将其副本添加到数组。这意味着当您以删除音轨$ index,并且让默认行为接管时,一切都按预期工作。

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

这就是我要说的demonstrated in a plunker

+0

你可以发布更新的重播器吗?看起来这会导致相同的问题 - 因为它似乎不是问题是集合/对象键,但它与'$ index'相关,我希望它仍然不匹配。所以我很好奇,看看我错过了什么。它可以帮助其他与您发布相同问题的人更好地了解您的解决方案。 – KayakDave

+0

你是对的 - 我在这里忽略的一点是,这是使用'track by $ index'的替代方案。对于原语需要'track by $ index',但对于我的帖子中的播放列表示例,复制要包含两次的轨道比通过索引进行跟踪更有意义(因为重新排序是非常可能的要求)。 –

+0

现在有道理。感谢更新。如果你有时间,你可能会调整一些问题 - 现在你将你的问题总结为“如果你正在使用$ index索引,你如何正确地从ng-repeat数组中移除一个元素?”我认为你现在正在回答更广泛的问题。就这样,这一切都有助于后代:) – KayakDave

7

使用track by的一大优势是Angular不会触及其跟踪表达式没有改变的任何DOM元素。这是长ng-repeat列表中的巨大性能改进,以及添加track by的原因之一。

性能优化是您所看到的根源。

当您使用track by$index你告诉ng-repeat将比分扳成创建它的每个DOM元素是对ng-repeat第一次运行位置($index)。

因此,与色彩风格的红色元素被标记为0,1橙,黄色2 ...最后靛5

当角看着你告诉它来跟踪索引删除颜色并看到你再有一个索引#5(因为你的列表比以前短)。因此,它将删除具有“靛蓝”颜色风格的标记为5的DOM元素。你仍然有一个索引#2,所以黄色的元素保持不变。

令人困惑的是,由于数据绑定,DOM元素中的文本确实被更新了。因此,当您删除“黄色”时,黄色的DOM元素将获得文本“绿色”。

总之你看到的是ng-repeat离开,因为它是跟踪值(2)仍然存在,但数据绑定更新了该元素中的文本与黄色不变风格的DOM元素。

为了增加与您需要将您的唯一标识符添加到您使用的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

+0

谢谢,这是一个非常彻底的解释。按颜色跟踪我的运动员,但是按$ index放置轨迹的原因是我可以在列表中重复元素。 '按颜色跟踪'意味着我不能有'[“红色”,“蓝色”,“红色”) - 有替代品吗? **编辑**我意识到我应该在我的plunkr列表中包含一个副本,以便让我的问题更清晰;) –

+0

您可以。我更新了答案以涵盖处理多个元素(使用唯一标识符)。 – KayakDave