2013-11-27 80 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