角度:自定义过滤器无限摘要

Angular: custom filter infinite digest

本文关键字:无限 过滤器 自定义 角度      更新时间:2023-09-26

我有一个自定义过滤器,它接受一个对象,主题,并返回一个全新的对象,结果。 过滤器是从 ng 重复调用的。 我的自定义过滤器可以工作,但会引发无限$digest错误。 这是我的过滤器:

   return function(subjectBin, field) {
    var result = {},
        faculty,
        subject;
    angular.forEach(subjectBin, function (value, key) {
        faculty = key;
        angular.forEach(value, function (value, key) {
            subject = key;
            value.forEach(function (course) {
                // Check "field" against some of the object's properties
                //
                if (course.asString.toUpperCase().indexOf(field) > -1 ||
                    course.subjectTitle.toUpperCase().indexOf(field) > -1 ||
                    faculty.toUpperCase().indexOf(field) > -1 ) {
                    if (result.hasOwnProperty(faculty)) {
                        if (result[faculty].hasOwnProperty(subject)) {
                            result[faculty][subject].push(course);
                        }
                        else {
                            result[faculty][subject] = [course];
                        }
                    }
                    else {
                        result[faculty] = {};
                        result[faculty][subject] = {};
                        result[faculty][subject] = [course];
                    }
                }
            });
        });
    });
    return result;
    };

据我了解,这会产生无限$digest错误,因为我的过滤器每次发生$digest周期时都会返回一个全新的对象。 这导致脏位再次设置,一次又一次......

但是当我看到这样的例子时,我会感到困惑:

  .filter('reverse', function() {
return function(input, uppercase) {
  input = input || '';
  var out = "";
  for (var i = 0; i < input.length; i++) {
    out = input.charAt(i) + out;
  }
  // conditional based on optional argument
  if (uppercase) {
    out = out.toUpperCase();
  }
  return out;
};
})

这是 Angular 文档中的一个例子,它清楚地接受了输入并返回了一个全新的字符串。也不会抛出任何无限$digest错误。 在我看来,这类似于我的过滤器,因为它返回了一个全新的对象。

关于为什么我的过滤器抛出无限$digest错误,但另一个过滤器没有

在你的代码片段中,你似乎正在从根本上改变你的数据结构。

角度滤镜不是为了对对象进行深度更改。顾名思义,它们意味着过滤信息。如果你的数据操作需要你改变数据结构,你可能做错了。

事实上,在它的循环摘要中,Angular 足够聪明,可以成功地比较,它本身:

  • 任何类型的字符串(文本和字符串对象)-- "foo" equals new String("foo")

  • 一维数组按其元素['a', 'b', 'c'] equals new Array(['a', 'b', 'c'])

  • 一维对象按其元素foo={a:'a', b:'b'} equals bar={a:'a', b:'b'}

但是,多维数组或对象开始变得混乱。例如,从过滤器返回像这样的新数组['a', 'b', ['c', 'd']]的内容将导致摘要循环中的无限循环,因为将oldValueNewValue进行比较总是错误的。你可以说Angular进行了肤浅的比较。

综上所述,在过滤器中返回新的多维对象或数组将达到无限$digest错误。


那么,如果我有一个复杂的多维数据结构,并且我需要在深层次上执行一些比较,该怎么办?

如果您没有在每个周期中创建新对象,那么没有什么可以阻止您进行深入比较。但是,数据应正确结构化。

例如,在您的情况下,您似乎正在使用对象作为键盘映射,如下所示:

var subjectBin = {
        faculty1: {
            subject1: ['math'],
            subject2: ['science', 'history'],
            subject3: ['foo', 'blabla'],
            subject4: ['unraveling', 'the mistery']
        },
        faculty2: {
            subject1: ['that', 'all'],
            subject2: ['started', 'with a'],
            subject3: ['foo', 'blabla'],
            subject4: ['bigbang', 'BANG!']
        }
    };

这是一个难以过滤的结构,因为没有通用模式(实际上,在您的过滤器中,您使用了 3 个循环!!)。

您可以像这样重组信息:

var subjectBin = [{
        facultyName: 'faculty1',
        subjects: [{
            subjectName: 'subject1',
            courses: ['math']
        }, {
            subjectName: 'subject2',
            courses: ['science', 'history']
        }]
    }];

这将更容易使用。实际上,您甚至不需要自定义过滤器,您可以使用默认的角度过滤器进行简单的比较

下面是一个数据重构逻辑(小提琴)的示例。

var app = angular.module('app', []);
app.controller('fooCtrl', ['$scope',
  function($scope) {
    var bla = {
      faculty1: {
        subject1: ['math'],
        subject2: ['science', 'history'],
        subject3: ['foo', 'blabla'],
        subject4: ['unraveling', 'the mistery']
      },
      faculty2: {
        subject1: ['that', 'all'],
        subject2: ['started', 'with a'],
        subject3: ['foo', 'blabla'],
        subject4: ['bigbang', 'BANG!']
      }
    };
    $scope.items = [];
    angular.forEach(bla, function(value, key) {
      var faculty = {
        name: key,
        subjects: []
      };
      angular.forEach(value, function(value, key) {
        var subject = {
          name: key,
          courses: value
        };
        faculty.subjects.push(subject);
      });
      $scope.items.push(faculty);
    });
  }
]);
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>
<div ng-app='app'>
  <div ng-controller="fooCtrl">
    <ul>
      <li ng-repeat="faculty in items">Faculty Name: {{faculty.name}}
        <br/>
        <ul>
          <li ng-repeat="subject in faculty.subjects | filter:{courses:['foo']}">Subject name: {{subject.name}}
            <br/>
            <ul>
              <li ng-repeat="course in subject.courses">{{course}}</li>
            </ul>
          </li>
        </ul>Subjects: {{item.subjects}}</li>
    </ul>
  </div>