简体   繁体   English

AngularJS-通过在复选框中使用嵌套对象来过滤数组

[英]AngularJS - Filter array by using nested objects in check boxes

I need to filter an array by using nested objects, it means filter the array by using multiple check boxes but I have an issue with the duplicate names. 我需要通过使用嵌套对象来过滤数组,这意味着要通过使用多个复选框来过滤数组,但是名称重复存在问题。 This is the source code I've been trying to use. 这是我一直在尝试使用的源代码

Any idea about how to fix the duplicate names issue? 关于如何解决重复名称问题的任何想法吗?

html html

<div data-ng-app="myApp">
<div data-ng-controller="controller">

<strong>Pick a brand to see the models</strong>
<div ng-init="group = (cars | groupBy:'make')">
    <div ng-repeat="m in group">
        <b><input type="checkbox" checked="true" ng-model="useMakes[$index]"/>{{m.name}}</b>
    </div>
</div>

<br/>
<table border="1">
    <thead>
       <tr>
           <th>#</th>
           <th>Name</th>
    <th>Maker</th>
  </tr>
</thead>
<tbody>
  <tr ng-repeat="car in cars | filter:filterMakes()">
    <td>{{$index+1}}</td>
    <td>{{car.make.name}}</td>
    <td>{{car.model}}</td>
  </tr>
</tbody>

js js

var myApp = angular.module('myApp',[]);

myApp.controller("controller", function($scope){
    $scope.useMakes = [];

    $scope.filterMakes = function () {
        return function (p) {
        for (var i in $scope.useMakes) {
             if (p.make == $scope.group[i] && $scope.useMakes[i]) {
             return true;
             }
        }
    };
 };

 $scope.makes = [
     {id:1, name: "BMV"},
     {id:2, name: "Ford"},
     {id:3, name: "Renault"},
     {id:4, name: "Seat"},
     {id:5, name: "Opel"}
 ];

 $scope.cars = [
     {model: '316', make: {id: 1, name: "BMV"}},
     {model: '520', make: {id: 1, name: "BMV"}},
     {model: 'Fiesta', make: {id: 2, name: "Ford"}},
     {model: 'Focus', make: {id: 2, name: "Ford"}},
     {model: 'Clio', make: {id: 3, name: "Renault"}},
     {model: 'Toledo', make: {id: 4, name: "Seat"}},
     {model: 'Leon', make: {id: 4, name: "Seat"}},
     {model: 'Insignia', make: {id: 5, name: "Opel"}},
     {model: 'Astra', make: {id: 5, name: "Opel"}},
     {model: 'Corsa', make: {id: 5, name: "Opel"}}
 ];

 });

 /*I think here is the problem*/
 var uniqueItems = function (data, key) {
     var result = new Array();
     for (var i = 0; i < data.length; i++) {
     var value = data[i][key];

    if (result.indexOf(value) == -1) {
        result.push(value);
    }

 }
 return result;
 };

 myApp.filter('groupBy', function () {
     return function (collection, key) {
     if (collection === null) return;
     return uniqueItems(collection, key);
     };
});

You can use the 'unique' filter 您可以使用“唯一”过滤器

   <div ng-repeat="m in group | unique:'name'">
            <b><input type="checkbox" checked="true" ng-model="useMakes[$index]"/>{{m.name}}</b>
   </div>

DEMO 演示

You could use the unique filter from AngularUI (source code available here: AngularUI unique filter ) and use it directly in the ng-options (or ng-repeat). 您可以使用AngularUI中的唯一过滤器(此处提供源代码: AngularUI唯一过滤器 ),然后直接在ng-options(或ng-repeat)中使用它。

<select ng-model="orderProp" ng-options="place.category for place in places | unique:'category'">
    <option value="0">Default</option>
    // unique options from the categories
</select>

The root of problem is that when using indexOf in the uniqueItems() , the object reference (aka memory address) is being used for comparison to check whether something is already in the array. 问题的根源在于,在uniqueItems()使用indexOf时,将使用对象引用(即内存地址)进行比较,以检查数组中是否已存在某些对象。

The effor to uniqify won't work as expected because the $scope.cars[0].make and $scope.cars[1].make are declared at 2 different places and hence will be created as 2 diffferent object references. 由于$scope.cars[0].make$scope.cars[1].make在2个不同的位置声明,因此将其唯一化的效果无法按预期进行,因此将其创建为2个不同的对象引用。

There are two possible solutions: 有两种可能的解决方案:

Alternative Solution #1 (preferred) : make every make in the $scope.cars to refer to objects that are already declared in the $scope.makes . 另一种解决方案#1(首选):尽一切make$scope.cars指的是在已经声明的对象$scope.makes This is the preferred solution because you will have one central place that specifies what the make names are ( Single Source Of Truth ), ie you only need to change one place if later you want to fix the "BMV" to "BMW". 这是首选的解决方案,因为您将在一个中心位置指定品牌名称( “真相单一来源” ),即,如果以后要将“ BMV”固定为“ BMW”,则只需更改一个位置。

$scope.cars = [
  {model: '316', make: $scope.makes[0]},
  {model: '520', make: $scope.makes[0]},
  {model: 'Fiesta', make: $scope.makes[1]},
  {model: 'Focus', make: $scope.makes[1]},
  {model: 'Clio', make: $scope.makes[2]},
  {model: 'Toledo', make: $scope.makes[2]},
  {model: 'Leon', make: $scope.makes[3]},
  {model: 'Insignia', make: $scope.makes[4]},
  {model: 'Astra', make: $scope.makes[4]},
  {model: 'Corsa', make: $scope.makes[4]}
];

Alternative Solution #2 : if you want to keep the $scope.cars for some reasons, we need to fix the $scope.filterMakes() and uniqueItems() to only compare the unique attribute of make instead of the make object reference. 替代解决方案#2 :如果出于某些原因要保留$scope.cars ,我们需要修复$scope.filterMakes()uniqueItems()以仅比较make的唯一属性而不是make对象引用。 In this case, we can compare the make.id . 在这种情况下,我们可以比较make.id

$scope.filterMakes = function () {
    return function (p) {
        for (var i in $scope.useMakes) {
            if (p.make.id == $scope.group[i].id && $scope.useMakes[i]) {  //add the ".id"
                return true;
            }
        }
    }
};

var uniqueItems = function (data, key) {
    var result = new Array();
    var added = []; //same as new Array();
    for (var i = 0; i < data.length; i++) {
        var value = data[i][key];
        if (added.indexOf(value.id) == -1) { //look for the id
            result.push(value);
            added.push(value.id); //list of added ids
        }
    }

    return result;
};

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM