AngularJS过滤器中的无限循环问题

18

我编写了一个用于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 是布尔类型。


1
你能同时发布你的HTML代码吗? - Abhilash Augustine
你有一个 ng-repeat-end 标签吗? - Phil
是的@Phil,我有ng-repeat-end - shmuli
3个回答

10
我编写了这个AngularJS自定义过滤器,但是当它运行时,出现了无限循环错误。请记住,过滤器应返回相同对象结构的数组。当我们激活过滤器时,它会触发digest循环,然后再次运行我们的过滤器。如果输出列表中有更改,则会触发新的digest周期,如此反复。在10次尝试后,它将抛出"Infinite Digest Loop"异常。
测试
这个空过滤器将起作用(100%)。实际上,我们在这里什么也不做,只需返回过滤器接收到的相同对象。
filter('department', function(filterFilter) {
  return function(items, args) {

    var output = items;

    return output;
  };
})

现在的主要想法是:编写一些条件来根据某些 if 语句从输入列表 a.e. items 将对象推入到 output 对象中。

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 map underscorejs map 等。


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/ 如果返回的数组与输入数组具有相同的“结构”,就会导致这些错误。在你的情况下,只需将原始项分配给返回的项即可使其正常工作。
if (productMatches.length !== 0) {
    output[count] = items[i]; // do this
    output[count].products = productMatches;
    output[count].firstProduct = items[i].firstProduct;
    count++;
}

1

output[count] = {};

上述代码是主要问题所在。你创建了一个新实例,而ng-repeat将检测到模型不断地无限改变。(尽管从UI的角度来看,你认为没有任何改变)

为避免出现此问题,基本上需要确保模型中的每个元素保持“相同”,即:

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

只要您不更改模型,这个等式就会保持不变,因此 ng-repeat 不会“错误地”认为模型已经改变。
请注意,两个新实例是不相等的,即 {} != {}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接