2013-11-27 81 views
8

我想对我的过滤器中的对象应用一个转换,这导致返回一个新对象的数组。这是因为我想在应用转换后过滤对象并显示转换结果。然而,我最终得到了无限的摘要,因为我显示的对象与我放入的对象不同(比较它们的$$ids时)。我的想法来解决这个如下:AngularJs - ngRepeat与返回一个新对象的过滤器

  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); 
    }     
    }] 
); 

这里是我怎么想使用它:

<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> 

哦,最好ngClick返回原来的对象,但我可以总是围绕它包装一个功能来查看。

+0

小提琴? Plunker? – Stewie

+0

我想我知道解决方案:)我正在处理它。 – m59

+0

你有'list.labels'的一些样本数据吗? – m59

回答

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} 
    ]; 

} 

由过滤器修改项目引起无限不管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> 

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

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

7

解决此问题的方法之一是由于对象ID的缘故,Angular具有幂等函数,它不是幂等的(因此会导致您提到的$ digest循环问题)为使用lo-dash /下划线的_.memoize缓存你的函数的结果

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

这里是你如何可以缓存你的过滤器的结果:

return _.memoize(function(objects, transformer, expression) { ... }, 
       function(objects,transformer,expression){ 
        return objects +transformer.name + expression; 
        }); 

一个适合您的情况重要的一点是,默认情况_.memoize使用第一个函数参数(objects在这种情况下)作为缓存键。由于您的过滤器在给定不同的转换函数和表达式时可能会产生不同的结果,因此我添加了可选的第二个参数 - 使用objects,expressiontransformer函数的名称生成缓存键的散列函数。

下面是使用此代码的简化版本:fiddle