带有轨道的ng-repeat中的函数导致Infinite $ digest-loop

H W*_*H W 12 javascript angularjs angularjs-ng-repeat

显然我还没有理解背后的机制ng-repeat,$$hashKeys而且track by.

我目前在我的项目中使用AngularJS 1.6.

问题:

我有一个复杂的对象数组,我想用它来渲染我的视图中的列表.但要获得所需的结果,我需要首先修改(或映射/增强/更改)这些对象:

const sourceArray = [{id: 1, name: 'Dave'}, {id:2, name: Steve}]

const persons = sourceArray.map((e) => ({enhancedName: e.name + e.id})) 

//Thus the content of persons is:
//[{enhancedName: 'Dave_1'}, {enhancedName: 'Steve_2'}]
Run Code Online (Sandbox Code Playgroud)

将此绑定到视图应该像这样工作:

<div ng-repeat="person in ctrl.getPersons()">
    {{person.enhancedName}}
</div>
Run Code Online (Sandbox Code Playgroud)

然而,这显然会进入$digest()-loop,因为.map每次调用它都会返回新的对象实例.由于我通过函数将其绑定到ng-repeat,因此它会在每个函数中重新评估$digest,模型不会稳定,Angular会保持重新$digest循环 - 因为这些对象被标记为$dirty.

为什么我很困惑

现在这不是一个新问题,有几个解决方案:

2012的Angular-Issue中, Igor Minar自己建议手动设置$$ hashKey-Property以告知angular生成的对象是相同的.是他的工作小提琴,但是因为即使这个非常简单的例子$digest在我的项目中使用它时仍然遇到了-loop,我尝试在小提琴中升级Angular-Version.由于某种原因它崩溃了.

好的......从Angular 1.3开始,我们track by应该从根本上解决这个问题.但两者都有

<div ng-repeat="person in ctrl.getPersons() track by $index">   
Run Code Online (Sandbox Code Playgroud)

<div ng-repeat="person in ctrl.getPersons() track by person.enhancedName">   
Run Code Online (Sandbox Code Playgroud)

$digest-loop 崩溃.我的印象是track by声明应该让角度相信它适用于相同的对象,但显然情况并非如此,因为它只是不断检查它们的变化.说实话,我不知道如何正确调试原因.

题:

是否可以使用过滤/修改的数组作为ng-repeat的数据源?

我不想将修改后的数组存储在我的控制器上,因为我需要不断更新其数据,然后必须在控制器中手动维护和刷新它,而不是依赖于数据绑定.

Bir*_*abs 2

你提供的“它崩溃了”小提琴并没有为我产生无限的摘要。事实上:它甚至没有成功引导 Angular 应用程序(看起来在最新的 Angular 中无法以这种方式引导)。

\n\n

重写了它以使用我理解的 Angular 引导机制。正如你所说,它重现了崩溃。

\n\n

我找到了一种通过字符串化 JSON成功跟踪它的方法。

\n\n

\r\n
\r\n
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.6.6/angular.min.js"></script>\r\n\r\n<script>\r\nangular.module(\'myApp\',[])\r\n.controller(\'Ctrl\', [\'$scope\', function($scope) {\r\n    angular.extend($scope, {\r\n    stringify: function(x) { return JSON.stringify(x) },\r\n    getList: function() {\r\n      return [\r\n        {name:\'John\', age:25},\r\n        {name:\'Mary\', age:28}\r\n      ];\r\n    }\r\n  });\r\n}]);\r\n</script>\r\n\r\n<div ng-app="myApp">\r\n\r\n<div ng-controller="Ctrl">\r\n  I have {{getList().length}} friends. They are:\r\n  <ul>\r\n    <li ng-repeat="friend in getList() track by stringify(friend)">\r\n      [{{$index + 1}}] {{friend.name}} who is {{friend.age}} years old.\r\n    </li>\r\n  </ul>\r\n</div>\r\n\r\n</div>
Run Code Online (Sandbox Code Playgroud)\r\n
\r\n
\r\n

\n\n

即我们提供跟踪功能stringify()。可能也有一个 Angular 内置函数可以实现这一点。

\n\n

track by $index与您的发现相反,\xe2\x80\x94 也有效。我认为 JsFiddle 稍微破坏了实验*

\n\n

*以下内容为轶事。我相信我在JsFiddle 本身上遇到了一些问题。例如:我的track by stringify()示例不起作用,直到我分叉 Fiddle 并在新的浏览上下文中再次尝试相同的代码。我相信,一旦我得到任何无限摘要:JsFiddle 总是无限摘要。似乎之前的跑步中还残留着一些庄严的感觉。所以,我建议您在 JsFiddle 中看到的任何失败,您在新的 JsFiddle 中重试

\n\n

至于为什么你的$$hashKey技巧会导致无限摘要 \xe2\x80\x94 我认为 Angular 不希望$$hashKey成为一个函数。因此,它可能不是调用您的函数,而是对分配给 的函数进行了引用比较$$hashKey

\n\n

由于每次调用时都分配给比较器的新实例$$hashKey:后续摘要中的引用永远不会相等,因此它将永远继续尝试摘要。getList()

\n\n

编辑:更新了 StackOverflow 嵌入和 JsFiddle 以使用 HTTPS CDN(以避免与混合内容安全性发生冲突)。

\n