2016-04-15 178 views
0

如何通過另一個數組中存在的屬性過濾數組?如何在AngularJS中實現過濾器?

我在我的控制這兩個數組:

this.items = [{ "Id": 1, "TypeId": 1, "name": "Michael" }, 
       { "Id": 2, "TypeId": 2, "name": "Helga" }, 
       { "Id": 3, "TypeId": 1, "name": "Max" }, 
       { "Id": 4, "TypeId": 2, "name": "Ann" }]; 

this.filterBy = [{ "Id": 1, "gender": "Male" }, 
       { "Id": 2, "gender": "female" }]; 

,這裏是我的NG-重複在視圖模板:

<tr ng-repeat="item in list.items"> 
    <td> 
     <div class="container-fluid"> 
      <div class="row"> 
       <div class="text-center">{{ item.name }}</div> 
      </div> 
     </div> 
    </td> 
</tr> 

這裏是生成的觀點:

Enter image description here

在某些時候,我想按性別過濾項目數組以顯示我上面的視圖僅限於女性或僅男性。

我試圖執行過濾器,像這樣:

(function() { 

    "use strict"; 

    angular.module("sensorsData").filter('filterByGender', filterByGender); 

    function filterByGender() { 
     var result = []; 
     return function (items, filterBy) { 
      if (!items) 
       return; 
      if (!filterBy) 
       return; 

      angular.forEach(items, function (item) { 
       angular.forEach(filterBy, function (f) { 
        if (item.TypeId == f.Id) { 
         result.push(item); 
        } 
       }) 
      }); 
      return result; 
     } 
    }; 
})(); 

在這裏,我如何使用它在視圖模板:

<tr ng-repeat="item in list.items | filterByGender:list.filterBy"> 
    <td> 
     <div class="container-fluid"> 
      <div class="row"> 
       <div class="text-center">{{ item.name }}</div> 
      </div> 
     </div> 
    </td> 
</tr> 

的情況下,所需的視圖如果filterBy陣列那樣的內容:

this.filterBy = [{ "Id": 1, "gender": "Male" }]; 

該視圖應僅顯示TypeId = 1的項目行。

像這樣:

Enter image description here

但上面的過濾器不能正常工作。

並在調試我得到這個錯誤:

Error: [ngRepeat:dupes] Duplicates in a repeater are not allowed. Use 'track by' expression to specify unique keys. Repeater: r in list.arr | filterByAlert:list.filterBy, Duplicate key: object:8, Duplicate value: {"Id":1,"TypeId":1,"name":"Michael"} 
http://errors.angularjs.org/1.5.3/ngRepeat/dupes?p0=r%20in%20list.arr%20%7C…%3A8&p2=%7B%22Id%22%3A1%2C%22TypeId%22%3A1%2C%22name%22%3A%22Michael%22%7D 
    at angular.js:68 
    at ngRepeatAction (angular.js:28799) 
    at $watchCollectionAction (angular.js:16734) 
    at Scope.$digest (angular.js:16869) 
    at Scope.$apply (angular.js:17133) 
    at done (angular.js:11454) 
    at completeRequest (angular.js:11652) 
    at XMLHttpRequest.requestLoaded (angular.js:11593) 

爲什麼不工作的過濾器?我如何創建一個過濾器來按性別顯示項目?

這:

angular.js:13424 Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! 
Watchers fired in the last 5 iterations: [] 
http://errors.angularjs.org/1.5.3/$rootScope/infdig?p0=10&p1=%5B%5D 
    at angular.js:68 
    at Scope.$digest (angular.js:16907) 
    at Scope.$apply (angular.js:17133) 
    at done (angular.js:11454) 
    at completeRequest (angular.js:11652) 
    at XMLHttpRequest.requestLoaded (angular.js:11593)(anonymous function) @ angular.js:13424 
angular.js:17136 Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! 
Watchers fired in the last 5 iterations: [] 
http://errors.angularjs.org/1.5.3/$rootScope/infdig?p0=10&p1=%5B%5D 

這:

Uncaught Error: [$rootScope:infdig] 10 $digest() iterations reached. Aborting! 
    Watchers fired in the last 5 iterations: [] 

爲什麼不工作的過濾器?我如何創建一個過濾器來按性別顯示項目?

+2

是否有一個特別的原因,你不是'typeId'過濾列表?或者你已經把相關數據看作是另一個變量? – Jhecht

+0

@Jhecht,我需要根據filterBy數組中的更改過濾生成視圖中的數據。 – Michael

+1

「上面的過濾器無法正常工作」是什麼意思?結果是什麼?你期望什麼? –

回答

1

的問題是,您聲明中錯誤的地方result陣列。

function filterByGender() { 
    var result = []; 
    return function (items, filterBy) { 
     ... 
     return result; 
    } 
}; 

這裏的filterByGender功能是什麼構成了過濾功能,而匿名內部功能上3行開始是實際的過濾功能。角度調用filterByGender只需要一次,構建過濾器,然後在每次輸入更改時調用第二個函數。在您當前的代碼中,result數組總是相同的(即應用程序的生命週期中只存在一個數組),並且每次調用過濾器時,都會將這些項再次推入。過濾器然後返回這個數組充滿重複,你從Angular中得到錯誤。

你想要什麼,而不是是讓每次輸入更改結果,所以results應聲明和匿名函數,而不是filterByGender初始化。試試這個:

function filterByGender() { 
    return function (items, filterBy) { 
     var result = []; 
     ... 
     return result; 
    } 
}; 
+0

非常感謝!這花了我很多時間。 – Michael

1

您可以使用一些非常複雜的函數式過濾解決方案,但在我看來,最簡單的方法是創建一個包含您的視圖需要的項目的合併列表(即視圖模型)。這樣,您可以簡單地使用ng-repeat上的filter來過濾性別。

這裏有一個代碼片段:

var app = angular.module('myapp', []); 
 
app.controller('myctrl', function($scope) { 
 
    var items = [{ "Id": 1, "TypeId": 1, "name": "Michael" }, 
 
       { "Id": 2, "TypeId": 2, "name": "Helga" }, 
 
       { "Id": 3, "TypeId": 1, "name": "Max" }, 
 
       { "Id": 4, "TypeId": 2, "name": "Ann" }]; 
 

 

 
$scope.types = [{ "Id": 1, "gender": "Male" }, 
 
       { "Id": 2, "gender": "female" }]; 
 
    $scope.filterBy = $scope.types[0]; 
 

 
    var constructViewModel = function(items, types) { 
 
    $scope.mergedItems = []; 
 
    angular.forEach(items, function(i){ 
 
     var mergedItem = angular.copy(i); 
 
     var type = types.filter(function(t){return t.Id == i.TypeId})[0]; 
 
     mergedItem.gender = type.gender; 
 
     $scope.mergedItems.push(mergedItem); 
 
    }); 
 
    } 
 
    
 
    constructViewModel(items, $scope.types); 
 
});
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script> 
 
<div ng-app="myapp" ng-controller="myctrl"> 
 
    <span>Filter by gender: </span><select ng-model="filterBy" ng-options="t as t.gender for t in types"></select> 
 
    <div ng-repeat="item in mergedItems | filter: { gender: filterBy.gender } :true"> 
 
    <td> 
 
     <div class="container-fluid"> 
 
     <div class="row"> 
 
      <div class="text-center">{{ item.name }} {{item.gender}}</div> 
 
     </div> 
 
     </div> 
 
    </td> 
 
    </div> 
 
</div>

相關問題