AngularJs - ngRepeat,带有一个返回一个新对象的过滤器

jtf*_*ank 8 angularjs angularjs-ng-repeat angularjs-filter

我正在尝试将转换应用于我的过滤器中的对象,这会导致返回一个新对象数组.这是因为我想在应用变换后过滤对象并显示变换的结果.但是,我最终得到了一个无限的摘要,因为我显示的对象与我输入的对象不同(比较它们时$$ids).我想解决这个问题如下:

  1. 使用跟踪表达式track by item.id,并将原始对象分配ids给每个转换的对象.虽然我的所有对象目前都有id,但这似乎是一个坏主意,因为它使得过滤器不那么通用 - 原始对象必须具有id,转换不能设置id(因为它将被覆盖)等.

  2. 将原始对象分配$$id给已转换的对象.这似乎是hackish,基于我的理解$$id应该是只读的.

  3. 根据转换过滤的结果返回原始对象的子集.这可能会导致性能问题,因为需要在过滤器和显示表达式中应用转换,并且我必须循环回转换/过滤的项目以选择要返回的正确原始项目.

这是过滤器:

listModule.filter('ui.filter.transformFilter',
                 ['$filter',
                  '$id',
                   function($filter, $id)
  {
    var Filter = $filter('filter');
    return function(objects, transformer, expression) {
      // precondition- we need a list of objects
      if (!_.isArray(objects)) {
        return objects;
      }

      var transformed = [];
      for (var i = 0; i < objects.length; i++) {
        transformed[i] = transformer(objects[i]);
      }

      return filtered = Filter(transformed, expression);
    }                  
  }]
);
Run Code Online (Sandbox Code Playgroud)

以下是我尝试使用它的方法:

  <tr ng-repeat="item in list.items | ui.filter.transformFilter:list.transformerFunction:list.search" ng-click="list.select({'item': item})" class="list-item">
    <td ng-repeat="label in list.labels" ng-bind-html="item[label.key]"></td>
  </tr>
Run Code Online (Sandbox Code Playgroud)

哦,理想情况下ngClick返回原始对象,但我总是可以用它包围一个函数来查看它.

Kay*_*ave 7

这个问题的一个解决方案是你有一个幂等函数,因为对象ID认为Angular不是幂等的(因此导致你记下的$ digest循环问题)是使用lo-dash/underscore _.memoize来缓存你的函数的结果.

这将保证对于任何给定的缓存键,您的过滤器将始终返回完全相同的对象(包括$$id).这样你就不必玩游戏了$$id,你可以获得不必在每个$ digest循环上重新计算过滤结果性能优势.

以下是缓存过滤器结果的方法:

return _.memoize(function(objects, transformer, expression) { ... },
                 function(objects,transformer,expression){ 
                    return objects +transformer.name + expression;
                  });   
Run Code Online (Sandbox Code Playgroud)

对于您的情况,一个重要的注意事项是默认情况下_.memoize使用第一个函数参数(objects在本例中)作为缓存键.由于您的过滤器可能会产生给予不同变压器功能和表达不同的结果,我已经添加了可选的第二个参数-使用散列函数objects,expression和名transformer函数产生一个缓存键.

以下是使用此代码的简化版本: 小提琴


Ada*_*dam 2

Angular 用于angular.equals检测范围变化。跟踪表达式用于将数组项与 DOM 元素进行匹配,这样当您过滤或重新排序数组时,Angular 只会显示、隐藏或重新排序某些元素,而不是重建整个子树。

看看这个简单的例子: http: //jsfiddle.net/Nb8mX/

function Ctrl($scope) {

    $scope.transform = function(item) {
        item.abc *= 2;
        return true;
    };

    $scope.data = [
        {abc: 123, def: 1},
        {abc: 456, def: 2},
        {abc: 789, def: 3}
    ];

}
Run Code Online (Sandbox Code Playgroud)

通过过滤器修改项目会导致无限摘要循环track by,而不管 ,而在内部执行相同的ng-init操作不会出现问题:

<ul ng-app="blah" ng-controller="Ctrl">
    <li ng-repeat="item in data | filter : transform">{{ item.abc }}</li>
    <li ng-repeat="item in data | filter : transform track by item.def">{{ item.abc }}</li>
    <li ng-repeat="item in data" ng-init="transform(item)">{{ item.abc }}</li>
</ul>
Run Code Online (Sandbox Code Playgroud)

这表明您可以编写指令而不是过滤器。

如果有人知道更好的解决方案,我也很乐意学习。