AngularJS过滤器中的无限摘要循环

时间:2017-08-23 04:16:17

标签: angularjs angular-digest

我已经为AngularJS编写了这个自定义过滤器,但是当它运行时,我得到了无限的摘要循环错误。为什么会发生这种情况,我该如何纠正?

angular.module("app", []).
filter('department', function(filterFilter) {
  return function(items, args) {
    var productMatches;
    var output = [];
    var count = 0;

    if (args.selectedDepartment.Id !== undefined && args.option) {
      for (let i = 0; i < items.length; i++) {

        productMatches = items[i].products.filter(function(el) {
          return el.Order__r.Department__r.Id === args.selectedDepartment.Id;
        });

        if (productMatches.length !== 0) {
          output[count] = {};
          output[count].products = productMatches;
          output[count].firstProduct = items[i].firstProduct;
          count++;
        }

      }
    }
    return output;
  };
}).

这是相关的HTML:

<tr class='destination' ng-repeat-start='pickupAccount in pickupAccounts | department : {"selectedDepartment": selectedDepartment, "option": displayExclusive }'>
  <!-- td here -->
</tr>

displayExclusive是布尔值。

3 个答案:

答案 0 :(得分:10)

  

我已经为AngularJS编写了这个自定义过滤器,但是当它运行时,我得到了无限的摘要循环错误。

请记住,filter应该返回相同对象结构的数组。当我们激活过滤器时,它会触发将再次在我们的过滤器上运行的摘要循环。如果输出列表中的内容发生了变化 - 触发新的摘要周期等等。在10次尝试后,它会抛出我们Infinite Digest Loop例外

测试

这个空过滤器可以正常工作(100%)。实际上我们在这里什么都不做,但返回过滤器收到的同一个对象。

filter('department', function(filterFilter) {
  return function(items, args) {

    var output = items;

    return output;
  };
})

现在主要的想法是:写一些条件从输入列表a.e推送到output个对象。 items基于if语句,a.e。

var output = [];

if (args.selectedDepartment.Id !== undefined && args.option) {
   angular.forEach(items, function(item) {
       if(<SOME CONDITION>) {
          output.push(item);
        }            
    });
}

通过这种方式也可以。

我们的案例:

我们有这样的逻辑:

productMatches = items[i].products.filter(function(el) {
      return el.Order__r.Department__r.Id === args.selectedDepartment.Id;
    });

    if (productMatches.length !== 0) {
      output[count] = {};
      output[count].products = productMatches;
      output[count].firstProduct = items[i].firstProduct;
      count++;
    }

这里我们完全修改了存储在output中的对象。 因此,下一个摘要周期我们的items会一次又一次地改变。

结论

filter的主要目的是过滤列表而不是修改列表对象内容。

您编写的上述逻辑与数据操作有关,而与过滤无关。 department过滤器返回相同长度的项目。

为了实现目标,您可以使用lodash mapunderscorejs map作为例子。

答案 1 :(得分:2)

当您以与原始数组不匹配的方式操作返回的数组时,会发生这种情况。例如见:

.filter("department", function() {
    return function(items, args) {
        var output = [];

        for (var i = 0; i < items.length; i++) {
            output[i] = {};
            output[i] = items[i]; // if you don't do this, the next filter will fail
            output[i].product = items[i];
        }
        return output;
    }
}

您可以在以下简化的jsfiddle中看到它:https://jsfiddle.net/u873kevp/1/

如果返回的数组具有相同的结构&#39;作为输入数组,它将导致这些错误。

只需将原始项目分配给返回的项目,它就适用于您的情况:

if (productMatches.length !== 0) {
    output[count] = items[i]; // do this
    output[count].products = productMatches;
    output[count].firstProduct = items[i].firstProduct;
    count++;
}

答案 2 :(得分:1)

  

output[count] = {};

以上是主要问题。您创建了一个新实例,ng-repeat将检测到模型不断无限更改。 (虽然你认为从UI的角度来看没有任何改变)

为了避免这个问题,基本上你需要确保模型中的每个元素保持“相同”,即

firstCallOutput[0] == secondCallOutput[0]
&& firstCallOutput[1] == secondCallOutput[1]
&& firstCallOutput[2] == secondCallOutput[2]
...

只要您不更改模型,就应该保持这种相等性,因此ng-repeat不会“错误地”认为模型已被更改。

请注意,两个新实例不相等,即{} != {}