Angular - 达到 10 次 $digest() 迭代。创建数组的深层副本时中止

Posted

技术标签:

【中文标题】Angular - 达到 10 次 $digest() 迭代。创建数组的深层副本时中止【英文标题】:Angular - 10 $digest() iterations reached. Aborting when creation deep copy of array 【发布时间】:2017-09-02 08:47:10 【问题描述】:

我想在表格标题中创建带有过滤器的表格。过滤器是每列中唯一值的列表。这是简化的代码:

<table>
  <tr>
       <th class="dropdown" ng-repeat="field in data.columns">
         <span>field.title</span>
         <ul class="dropdown-menu">
           <li ng-repeat="item in unique(data.items, field)"><checkbox> item.text</li>
         </ul>
       </th> 
  </tr>
  <tr ng-repeat="item in data.items"></tr>
</table>

我对过滤器和表使用相同的对象数组,但过滤器创建数组的副本并从重复的副本值中删除。这是我的问题。

当我将数组复制为array.slice(0) 时,删除的值不在过滤器中,而是在表中(数组包含对象)。我的问题出在引用中,所以我使用 deepcopy 作为 jQuery.extend(true, [], array) 并且 angular throws 错误:

[$rootScope:infdig] 达到 10 次 $digest() 迭代。中止! 在最后 5 次迭代中触发的观察者

我的数据如下所示:

[id: 1, title: 'AAA', something: [id: 1, text: "A"], id: 2, title: 'AAAA', something: [id: 2, text: "AA"]]

问题出在属性上(array.slice(0)donť 复制和 $.extend 复制但 angular get 错误)

感谢您的建议

【问题讨论】:

angular.copy() 角度方式。 我认为如果您将一些操作数组的逻辑移至控制器,您的问题就会消失。尝试将对 unique(data.items, field) 的调用移动到控制器函数。如果您可以减少其中一个 ng-repeat,那将显着减少摘要循环的数量。 另一种角度方法可能是使用 $filter('filter') 或为 ng-repeat 创建自定义过滤器。 【参考方案1】:

您还没有发布过滤器的代码,所以我必须假设发生了什么。我认为您没有在制作副本之前检查列表的所有元素是否都是唯一的。这会导致过滤器更改数据每个摘要,从而触发无限数量的摘要 - 因此出现错误。你的名单永远不稳定。

要在过滤器开始时解决这个问题,请添加检查元素的唯一性,如果它们已经是唯一的(例如在第一次通过过滤器之后),只需返回输入对象。这样模型就会稳定下来。

【讨论】:

【参考方案2】:

这是我从对象数组中获取唯一值的代码:

    function toUnique(a, property, innerProperty) 
        var lastIndex = a.length;
        if (lastIndex === 0 || lastIndex === undefined)
            return a;
        var copyarr = jQuery.extend(true, [], a);
        if (property !== undefined) 
            while (prevIndex = --lastIndex) 
                while (prevIndex--) 
                    var obj1 = copyarr[lastIndex];
                    var obj2 = copyarr[prevIndex];

                    if (obj1 !== undefined) 
                        if (copyarr[lastIndex][property] instanceof Array && copyarr[prevIndex][property] instanceof Array)
                            unique(copyarr[lastIndex][property], copyarr[prevIndex][property], innerProperty);
                        else
                            obj1[property] !== obj2[property] || copyarr.splice(prevIndex, 1);
                    
                
            
            return copyarr;
         else 
            while (prevIndex = --lastIndex)
                while (prevIndex--)
                    copyarr[lastIndex] !== copyarr[prevIndex] || copyarr.splice(prevIndex, 1);
            return copyarr;
        
    

function unique(array1, array2, innerProperty) 
    for (var i = 0; i < array1.length; i++) 
        removeDuplicates(array1, i + 1, array1[i], innerProperty);
        removeDuplicates(array2, 0, array1[i], innerProperty);
    
    for (var i = 0; i < array2.length; i++) 
        removeDuplicates(array2, i + 1, array2[i], innerProperty);
    


function removeDuplicates(arr, startPos, p, property) 
    for (var i = startPos; i < arr.length;) 
        if (p[property] == arr[i][property]) 
            arr.splice(i, 1);
         else 
            i++;
        
    

使用:

    var a = [id: 1, title: "AAAA", id: 2, title: "BBBB", id: 1, title: "AAAA"]
    unique(a, "title", null); //return id: 1, title: "AAAA", id: 2, title: "BBBB"

    var b = [id: 1, title: "AAAA", authors: [id: 15, name: "John", id: 25, name: "Peter", id: 16, name: "John"],
id: 1, title: "BBBB", authors: [id: 15, name: "John", id: 25, name: "Peter]]

    unique(b, "authors", "name")  //return: [id: 1, title: "AAAA", authors: [id: 15, name: "John", id: 25, name: "Peter],
id: 1, title: "BBBB", authors: []]

【讨论】:

检查if (lastIndex === 0 || lastIndex === undefined)后,还要检查所有元素是否已经唯一,如果是,返回a。您也可以考虑使用 linq.jslodash 这样的库,其中已经实现了唯一检查。

以上是关于Angular - 达到 10 次 $digest() 迭代。创建数组的深层副本时中止的主要内容,如果未能解决你的问题,请参考以下文章

Angular - 达到 10 次 $digest() 迭代。创建数组的深层副本时中止

如何解决 Angular “10 $digest() 迭代次数达到”错误

ng-repeat:达到 10 次 $digest() 迭代

AngularJs - 错误:达到 10 次 $digest() 迭代。中止

错误:达到 10 次 $digest() 迭代。中止

达到 10 次 $digest() 迭代。中止! - 隔离范围