2015-07-01 17 views
0

我想出了在角1.3一个非常怪异的行为:怪异的行为角1.3时NG-重复拷贝项目

它发生时,我改变

{{item}} 

到:

{{::item}} 

并点击“复制”按钮;它想要做的是复制给定索引处的项目并将其放在源项目下。它所做的是复制列表中的最后一项并将其添加到列表的底部!

HTML:

<div ng-app="myApp"> 
    <div ng-controller="MyCtrl"> 
     <ul> 
      <li ng-repeat="item in items track by $index">{{::item}}</li> 
     </ul> 
     <input ng-model="newItem" type="text"></input> 
     <button ng-click="add(newItem)">Add</button> 
     <button ng-click="copy(newItem)">Copy</button> 
    </div> 
</div> 

的JavaScript:

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

app.controller('MyCtrl', function($scope) { 
    $scope.items = ["A", "B", "C", "D"]; 
    $scope.add = function(item) { 
     $scope.items.push(item); 
    }; 
    $scope.copy = function(item) { 
     var newItem = angular.copy($scope.items[parseInt(item)]); 
     $scope.items.splice(parseInt(item) + 1, 0, newItem); 
    };  
}); 

任何人都知道什么是引擎盖下回事?

这里是一个小提琴:http://jsfiddle.net/v87kgwud/14/

+0

它如何知道索引? –

+0

如果您打开JSFiddle;因为您可以看到该项目应该在文本框中输入。 I.E.当您键入0并单击复制时,它应复制“A”并将其放在源项目下。 –

+0

基本上,我认为AngularJS不会在DOM中插入一个新项目,它只会在最后插入它,并更新相应的作用域。但由于文本内容不能改变(因为一次性绑定),所以在复制之前和之后都看不到差异。我仍然在为您寻找解决方案,以及我正在说的一些证据。 – Blackhole

回答

-1

这里是我的角度documentation发现:
与::被认为是一次性的表达式开始的表达式。一次性表达式一旦稳定就会停止重新计算。

这实际上意味着当页面被渲染并且ng-repeat运行时,迭代会正确发生并且值按正确的顺序打印。一旦ng-repeat结束,分配给{{:: item}}的值为'D'。如果收集长度发生变化,ng-repeat将添加一个新项目,但该项目每次都是D,因为{{:: item}}解析为D.无论复制函数是否正常工作并添加了正确的元素到集合中。所以,你的收藏不再是真相的来源。这是一次性绑定的意思 - 你不再连接到源代码。以下是完整的逐字记录: 为什么使用此功能 一次性绑定表达式的主要目的是提供一种方法来创建绑定,一旦绑定稳定后就会取消注册并释放资源。减少正在观看的表达式的数量使摘要循环更快,并允许同时显示更多信息。

为什么这个功能

一次性绑定表达式的主要目的是提供一种方法来 创建被注销并释放一次 结合稳定的资源约束。减少所观看的表达式数量 使得摘要循环更快,并允许同时显示更多信息为 。

值稳定算法

一次性绑定表达式,只要该值不是未定义在消化周期结束将保留表达 的值。 如果表达式的值在摘要循环中设置,并且在同一摘要循环中设置为未定义,则 表达式不会被满足并且将保持监视。

  1. 鉴于与::开始的表达式中,当输入了消化环和表达是脏检查,存储该值为V
  2. 如果V不是未定义,标记表达稳定的结果并计划任务注销手表这个表达式时 我们退出摘要循环
  3. 过程中的消化循环正常
  4. 当消化循环完成,所有的价值观都尘埃落定,过程的手表注销任务队列中。对于每个手表取消注册为 ,请检查它是否仍然评估为未定义的值,不是 。如果是这种情况,请注销手表。否则,保持 脏检查在今后的手表通过遵循 相同的算法,从第1步
+0

由于复制按钮正在迭代,此解决方案不正确。我不想那样。 –

+0

在downvoting之前,请检查您自己的代码。我只是在玩弄你的小提琴。无论如何,请看我更新的答案。 –

+0

我没有downvoted你的答案的方式... –

0

开始我觉得Sidharth Panwar的回答是,除了一个在大多数情况下正确的消化循环。

说明: 列表的初始状态是['A', 'B', 'C', 'D']和前4个元素是一个时间限定(即,在其值的变化将不会对UI反射的),但在任何情况下,如果输入范围是0-3,一个新元素被添加到列表中,并且列表中的最后一个字符'D'被推到第五位。由于列表中第五位的项目不是一次限定的,所以列表中将呈现一个新的D.

跟踪

  1. 初始状态:['A', 'B', 'C', 'D']
  2. 复制 'A' 通过给0作为输入到文本框
  3. 新状态:['A','A','B', 'C','D']

由于前4个元素是一次有界的,列表不会改变在第一个摘要循环中绑定的值,但是由于在第五个元素中找到了新元素,所以必须对该新元素执行一次绑定。

在列表中D处添加任何元素会将最后一个元素移动一个位置,因为这个新元素没有绑定,所以会创建一个时间边界。但在这种情况下,新元素似乎总是'D',因为它位于列表的尾部。

希望这会有所帮助!

+0

我认为你的解释更有意义,但实际上对我的问题仍然没有答案。在我的代码中,我复制了$ scope.items [parseInt(item)]指向当时正确的项目。此外,当我填写“X”并按下“Ädd”按钮时,最后会添加正确的值。它为什么不起作用仍然是一个谜! –