【问题标题】:Grouping javascript array items based on their properties with AngularJS使用 AngularJS 根据属性对 javascript 数组项进行分组
【发布时间】:2019-05-14 13:14:08
【问题描述】:

想象一下有一份葡萄酒清单:

[  
   {  
      "name":"wine A",
      "category":[  
         "red",
         "merlot"
      ]
   },
   {  
      "name":"wine B",
      "category":[  
         "white",
         "chardonnay"
      ]
   },
   {  
      "name":"wine C",
      "category":[  
         "white",
         "chardonnay",
         "red",
         "merlot"
      ]
   }
]

我需要用AngularJS创建一个过滤/分组机制,这样如果用户选择“霞多丽”,结果会是:

Results: wine B, wine C

我有一个工作示例,但请检查该示例的结构数据。没有定义对象项中的数组。我应该在控制器中进行什么调整以使其与上述(数组)结构兼容?

var app = angular.module("myApp", []);
app.controller("myCtrl", function($scope) {
  $scope.wines = [
    {
      name: "Wine A",
      category: "red"
    },
    {
      name: "Wine B",
      category: "red"
    },
    {
      name: "wine C",
      category: "white"
    },
    {
      name: "Wine D",
      category: "red"
    },
    {
      name: "Wine E",
      category: "red"
    },
    {
      name: "wine F",
      category: "white"
    },
    {
      name: "wine G",
      category: "champagne"
    },
    {
      name: "wine H",
      category: "champagne"
    }
  ];
  $scope.filter = {};

  $scope.getOptionsFor = function(propName) {
    return ($scope.wines || [])
      .map(function(w) {
        return w[propName];
      })
      .filter(function(w, idx, arr) {
        return arr.indexOf(w) === idx;
      });
  };

  $scope.filterByProperties = function(wine) {
    // Use this snippet for matching with AND
    var matchesAND = true;
    for (var prop in $scope.filter) {
      if (noSubFilter($scope.filter[prop])) continue;
      if (!$scope.filter[prop][wine[prop]]) {
        matchesAND = false;
        break;
      }
    }
    return matchesAND;
    /**/
    /*
            // Use this snippet for matching with OR
            var matchesOR = true;
            for (var prop in $scope.filter) {
                if (noSubFilter($scope.filter[prop])) continue;
                if (!$scope.filter[prop][wine[prop]]) {
                    matchesOR = false;
                } else {
                    matchesOR = true;
                    break;
                }
            }
            return matchesOR;
    /**/
  };

  function noSubFilter(subFilterObj) {
    for (var key in subFilterObj) {
      if (subFilterObj[key]) return false;
    }
    return true;
  }
});

app.filter("capitalizeFirst", function() {
  return function(str) {
    str = str || "";
    return str.substring(0, 1).toUpperCase() + str.substring(1).toLowerCase();
  };
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.5/angular.min.js"></script>
<div ng-app="myApp">
  <div ng-controller="myCtrl">
    <div ng-repeat="(prop, ignoredValue) in wines[0]" ng-init="filter[prop]={}">
      <b>{{prop | capitalizeFirst}}:</b>
      <br />
      <span class="quarter" ng-repeat="opt in getOptionsFor(prop)">
        <input type="checkbox" ng-model="filter[prop][opt]" />&nbsp;{{opt}}
      </span>
      <hr>
    </div>
    <div ng-repeat="w in filtered=(wines | filter:filterByProperties)">
      {{w.name}} ({{w.category}})
    </div>
    <hr> Number of results: {{filtered.length}}
  </div>
</div>

【问题讨论】:

  • 您的意思是以前您的列表为{ name: "Wine A", category: "red" } 现在它是{ "name":"wine A", "category":[ "red", "merlot" ] }
  • @Moshii 没错!

标签: javascript arrays angularjs json grouping


【解决方案1】:

只需使用search 过滤器:

 <b>Pick your category: (Hard coding)</b>
            <ul>
              <li style="cursor:pointer" ng-click="click_filter('red')">red</li>
              <li style="cursor:pointer" ng-click="click_filter('merlot')">merlot</li>
              <li style="cursor:pointer" ng-click="click_filter('white')">white</li>
              <li style="cursor:pointer" ng-click="click_filter('chardonnay')">chardonnay</li>
            </ul>

    <b>Result</b>
          <div ng-repeat="wine in wines | filter:search ">
          <b>{{wine.name}}</b> - (category): {{wine.category}}
          </div>
    </div>

JS:

 $scope.click_filter = function(item) {
         $scope.search = item;
     }

还有什么要做(如果您不希望对类别进行硬编码)- 寻找如何从 ng-repeat 中删除重复条目(在我的 plunker 示例中存在这个问题)

plunker:http://next.plnkr.co/edit/POW2i0rkQhpcvZYh?preview

【讨论】:

    【解决方案2】:

    从列表移动到数组时,您必须修改检索选项的方式并添加对 flat() 的调用

      $scope.getOptionsFor = function(propName) {
        return ($scope.wines || [])
          .map(function(w) {
            return w[propName];
          })
          .flat()
          .filter(function(w, idx, arr) {
            return arr.indexOf(w) === idx;
          });
      };
    

    那么 filterByProperty 需要能够处理数组以及普通值:

      $scope.filterByProperties = function(wine) {
        // Use this snippet for matching with AND
        var matchesAND = true;
        for (var prop in $scope.filter) {
          if (noSubFilter($scope.filter[prop])) 
            continue;
    
          if(Array.isArray(wine[prop])) {
              let matchCount = 0;  
              for(let i in wine[prop]) {
                if ($scope.filter[prop][wine[prop][i]]) {
                  ++matchCount;
                }
              }
              let trueFilter = 0
              Object.values($scope.filter[prop]).forEach(element => {
                  if (element)
                    ++trueFilter
              });
              matchesAND = matchCount == trueFilter;
              if (! matchesAND)
                break
          }
          else {
          if (!$scope.filter[prop][wine[prop]]) {
            matchesAND = false;
            break;
          }}
        }
        return matchesAND;
      };
    

    【讨论】:

      猜你喜欢
      • 2021-11-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多