我想重复创建div,这些项目是函数返回的对象。但是,以下代码报告错误:达到10个$ digest()迭代。流产!jsfiddle在这里:http://jsfiddle.net/BraveOstrich/awnqm/
<body ng-app>
<div ng-repeat="entity in getEntities()">
Hello {{entity.id}}!
</div>
</body>
我想重复创建div,这些项目是函数返回的对象。但是,以下代码报告错误:达到10个$ digest()迭代。流产!jsfiddle在这里:http://jsfiddle.net/BraveOstrich/awnqm/
<body ng-app>
<div ng-repeat="entity in getEntities()">
Hello {{entity.id}}!
</div>
</body>
Answers:
简短的回答:您真的需要这样的功能还是可以使用属性?http://jsfiddle.net/awnqm/1/
长答案
为简单起见,我仅描述您的情况-ngRepeat对象数组。另外,我将省略一些细节。
AngularJS使用脏检查来检测更改。当应用程序启动时运行$digest
的$rootScope
。$digest
将对作用域的层次结构进行深度优先遍历。所有范围都有手表清单。每个手表都有最后一个值(最初是initWatchVal
)。对于所有手表的每个作用域都$digest
运行它,获取当前值(watch.get(scope)
)并将其与进行比较watch.last
。如果当前值不等于watch.last
(始终用于第一次比较),则$digest
设置dirty
为true
。如果处理所有范围,dirty == true
$digest
则从开始另一个深度优先遍历$rootScope
。$digest
当脏== false或遍历次数== 10时结束。在后一种情况下,错误“达到10 $ digest()迭代”。将被记录。
现在大约ngRepeat
。对于每次watch.get
调用,它将来自集合(返回值getEntities
)的对象与其他信息一起存储在缓存中(HashQueueMap
由hashKey
)。对于每个watch.get
调用,ngRepeat
尝试通过其hashKey
缓存获取对象。如果它在缓存中不存在,则将其ngRepeat
存储在缓存中,创建新的作用域,在其上放置对象,创建DOM元素,等等。
现在大约hashKey
。通常hashKey
是由生成的唯一编号nextUid()
。但这可以起作用。hashKey
生成后存储在对象中以供将来使用。
为什么您的示例会产生错误:函数getEntities()
总是返回带有新对象的数组。该对象hashKey
在ngRepeat
缓存中不存在也不存在。因此ngRepeat
,每个watch.get
手表都会为for生成新的作用域{{entity.id}}
。这只手表先watch.get
有watch.last == initWatchVal
。这样watch.get() != watch.last
。因此$digest
开始新的遍历。因此ngRepeat
用新的手表创造了新的范围。所以... 10个遍历后,您会得到错误。
如何解决
getEntities()
调用时都创建新对象。hashKey
为其添加方法。有关示例,请参见本主题。希望知道AngularJS内部知识的人会在我做错事情时纠正我。
Do not create new objects on every getEntities() call.
可以很容易地将其固定:<div ng-repeat="entity in entities = (entities || getEntities())">
getEntities()
总是返回同一数组的情况下有效,如果该数组曾经更改,您将不会在ng-repeat
在重复序列之外初始化数组
<body ng-app>
<div ng-init="entities = getEntities()">
<div ng-repeat="entity in entities">
Hello {{entity.id}}!
</div>
</div>
</body>
getEntities()
返回的结果与程序的生命周期不同,则此方法不起作用。举例来说,这会getEntities()
触发$http.get
。当get最终解析(您进行了AJAX调用)时,entities
将已经初始化。
The only appropriate use of ngInit is for aliasing special properties of ngRepeat. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
这是在这里报告的,得到了以下响应:
您的吸气剂不是幂等的,它会更改模型(通过在每次调用时生成一个新数组)。这迫使Angular继续调用它,希望模型最终能够稳定下来,但是它从没有放弃,并引发异常。
getter返回的值相等但不相同,这就是问题所在。
如果将数组移到Main控制器之外,则可以看到这种现象消失了:
var array = [{id:'angularjs'}];
function Main($scope) {
$scope.getEntities = function(){return array;};
};
因为现在它每次都返回相同的对象。您可能需要重新设计模型,以在范围上使用属性而不是函数:
我们通过将控制器方法的结果分配给属性并对其执行ng:repeat来解决此问题。
基于@przno评论
<body ng-app>
<div ng-repeat="item in t = angular.equals(t, getEntities()) ? t : getEntities()">
Hello {{item.id}}!
</div>
</body>
BTW第二个解决方案@Artem Andreev建议在Angular 1.1.4及更高版本中不起作用,而第一个解决方案不能解决问题。因此,现在恐怕这是不那么尖锐的解决方案,并且在功能上没有缺点
Item.id
是应该的b。谢谢