【问题标题】:Custom filter on 'ng-repeat' does overwrite the scope'ng-repeat' 上的自定义过滤器会覆盖范围
【发布时间】:2016-11-07 12:42:31
【问题描述】:

我的目标是将一个输出数组的教师 ID(f_teacher)替换为另一个数组的教师姓名。我写了一个自定义过滤器,应该可以完成这项工作:

angular.module('core')
.filter('replaceId', function () {                   //filter, which replaces Id's of one array, with corresponding content of another array
    return function (t_D, s_D, t_prop, s_prop) {     //data of target, data of source, target property, source property
        var replacment = {};
        var output = [];
        angular.forEach(s_D, function (item) {
            replacment[item.id] = item[s_prop];      //replacment - object is filled with 'id' as key and corresponding value
        });
        angular.forEach(t_D, function (item) {
            item[t_prop] = replacment[item[t_prop]]; //ids of target data are replaced with matching value
            output.push(item);
        });
        return output;
    }
});

我使用这样的“ng-repeat”:

<tr ng-repeat="class in $ctrl.classes | filter:$ctrl.search | replaceId:$ctrl.teachers:'f_teacher':'prename' | orderBy:sortType:sortReverse">
    <td>{{class.level}}</td>
    <td>{{class.classNR}}</td>
    <td>{{class.f_teacher}}</td>
</tr>

但它只输出一个空列。现在奇怪的是:如果我按照调试器的步骤操作,它会在第一次执行过滤器时工作。但是当它第二次执行时,它会输出一个空列。

我注意到过滤器的返回对象覆盖了 $ctrl.classes - 数组,但通常情况下不应该是这种情况?

这是一个 plnkr: https://plnkr.co/edit/EiW59gbcLI5XmHCS6dIs?p=preview

为什么会这样?

感谢您的宝贵时间:)

【问题讨论】:

  • 你能用 plunker 重现这个问题吗?您的过滤器直接在$ctrl.classes 中的对象上设置字段。如果您不希望它更改$ctrl.classes,那么您可以对其中的对象执行angular.copy() 之类的操作。
  • 我添加了一个 plnkr(见上文)。好的,但是我使用其他自定义过滤器,它们的工作原理相同(修改数组并返回修改后的数组)并且它们不会覆盖范围。为什么这个自定义过滤器会这样做?

标签: javascript arrays angularjs angularjs-ng-repeat angularjs-filter


【解决方案1】:

第一次通过您的过滤器时,代码采用f_teacher id 并将其替换为教师姓名。第二次通过它尝试做同样的事情,除了现在而不是在f_teacher 中获取教师 ID,它找到了教师的名字,所以它不起作用。您可以通过制作类的副本而不是直接修改它们来修复它。例如

angular.forEach(t_D, function (item) {
    var itemCopy = angular.copy(item);
    itemCopy[t_prop] = replacment[itemCopy[t_prop]];
    output.push(itemCopy);
});

https://plnkr.co/edit/RDvBGITSAis3da6sWnyi?p=preview

编辑

原始解决方案将触发无限摘要,因为过滤器每次运行时都会返回对象的新实例,这将导致 Angular 认为某些内容已更改并重新触发摘要。你能不能只用一个 getter 函数来获取教师姓名而不是使用过滤器?

$scope.getTeacherName = function(id) {
  var matchingTeachers = $scope.teachers.filter(function(teacher) {
    return teacher.id == id;
  })

  //Should always be exactly 1 match.
  return matchingTeachers[0].prename;
};

然后在 HTML 中你可以像这样使用它

<tr ng-repeat="class in classes">
  <td>{{class.level}}</td>
  <td>{{class.classNR}}</td>
  <td>{{getTeacherName(class.f_teacher)}}</td>
</tr>

https://plnkr.co/edit/gtu03gQHlRIMsh9vxr1c?p=preview

【讨论】:

  • 谢谢!但现在我得到一个angular 10 $digest() iterations reached. aborting 错误。我不确定为什么它在 plnkr 中有效,但在我的应用程序中无效。自定义过滤器肯定是错误原因。
  • 没关系,plnkr javascript 也会抛出错误。
猜你喜欢
  • 2016-06-06
  • 1970-01-01
  • 2013-05-09
  • 1970-01-01
  • 2017-06-11
  • 1970-01-01
  • 2020-06-18
  • 2015-02-24
  • 1970-01-01
相关资源
最近更新 更多