为什么我的自定义过滤器会导致无限消化

Why is my custom filter causing infinite digestion?

本文关键字:无限 我的 自定义 过滤器 为什么      更新时间:2023-09-26

我创建了一个自定义过滤器,将键值对数组分解为一个对象,该对象按特定属性的第一个字母对值进行分组。例如

输入:[{foo: 'bar'}, {faz: 'baz'}, {boo: 'foo'}]

输出:{f: [{foo: bar}, {faz: baz}], b: [{boo, foo}]}

然而,这个过滤器似乎在 Angular 中导致了无限的消化错误。

var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function($scope){
  $scope.arr = [{name: 'foo', def: 'bar'}, {name: 'faz', def: 'baz'}, {name: 'boo', def: 'foo'}]
}]);
app.filter('firstLetterChunks', function() {
    return function(input){
        var chunks={};
        for(var i = 0; i < input.length; i++){
            var firstLetter = input[i].name[0].toUpperCase();
            if(!(chunks.hasOwnProperty(firstLetter))) {
                chunks[firstLetter]=[];
            }
            chunks[firstLetter].push(input[i]);
        }
        return chunks;
    };
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app="app">
  <div ng-controller="ctrl">
    This caused a infdig error. Check your console.
    <div ng-repeat="(firstletter, values) in arr | firstLetterChunks">
      {{firstletter}}
      <hr>
      <div ng-repeat="value in values">
        {{value}}
      </div>
    </div>
  </div>
</div>

我不知道为什么。据我发现,这通常是由于在过滤器中修改模型,从而重新触发 ng-repeat,但我认为我没有这样做。

发生这种情况是因为每个过滤器调用基本上都会返回一个新对象,该对象具有新的标识,因此 Angular 认为某些内容已更改。这反过来又会触发一个新的摘要周期,并一直持续到达到 10 个摘要限制。

我想还有其他方法可以通过使用缓存来存储计算对象并保留过滤器来修复它,但我将您的代码更改为以下工作原理相同的代码,但是如果数组发生变化,您必须重新计算chunks

var app = angular.module('app', []);
app.controller('ctrl', ['$scope', function($scope){
  $scope.arr = [{name: 'foo', def: 'bar'}, {name: 'faz', def: 'baz'}, {name: 'boo', def: 'foo'}];
    function getChunks() {
        var input = $scope.arr;
        var chunks = {};
        for(var i = 0; i < input.length; i++){
            var firstLetter = input[i].name[0].toUpperCase();
            if(!(chunks.hasOwnProperty(firstLetter))) {
                chunks[firstLetter]=[];
            }
            chunks[firstLetter].push(input[i]);
        }
        return chunks;
    }
    $scope.chunks = getChunks();
}]);

并将 HTML 调用更改为:

<div ng-repeat="(firstletter, values) in chunks">

小提琴