AngularJS filter list based on array properties

Viewed 68

How to create the following filter using AngularJS?

Here's a visual diagram explaining the question. I've been trying to figure this out for a bit and would really appreciate some help.

I have a list of companies:

$scope.companies = [ 
                     { 
                       id:"company_01",
                       ratings: [ 5, 5, 5, 5, 0, 5, 4, 4, 1, 3, 0, 0 ]
                     },
                     { 
                       id:"company_02",
                       ratings: [ 5, 4, 5, 4, 0, 5, 4, 4, 1, 3, 0, 0 ]
                     }
                     ...
                   ]; 

where each company has a property called ratings —- an array of numeric values (1-5) that represent scores for a given set of issues:

 $scope.issues = [
                  {
                    label:'Carbon Footprint', 
                    selected: true, 
                    value: 3
                  },

                  ...

                  {
                    label:'Consumer Health', 
                    selected: false, 
                    value: null
                  },

                  ...

                  {
                    label:'Employee Satisfaction', 
                    selected: true, 
                    value: 5
                  },

                  ...
                ];

The indices of $scope.companies[i].ratings correspond to the indices of $scope.issues.

Each issue has:

  • a selected property, a boolean toggled by a UI checkbox
  • a value property, a number (1-5) adjusted by a UI slider

I'd like to filter $scope.companies based on whether company.ratings[i] >= issue[i].value for each selected issue[i]. If an issue is not selected, it shouldn't affect the filter.

A related question is what the best way to watch for changes on $scope.issues would be. e.g. when a user selects/deselects an issue or adjusts a slider.

Thanks very much!

2 Answers

The Filter

Here's a goodRatingsOnly filter that filters the $scope.companies array based on the contents of the $scope.issues array. With several loops, it searches for a reason to not return the record i.e. when a poor rating is found.

  app.filter("goodRatingsOnly", function thisFilter() {
    return function(companies, issues){
      return companies.filter(function(comp){
        var poorRatingFound = false;
        issues.forEach(function(issue, i){  
          if (issue.selected){
            if (!poorRatingFound){
              poorRatingFound = comp.ratings[i] < issue.value;
              console.log(poorRatingFound);
            }
          }
        });
        return !poorRatingFound;
      });
    }
  });

Sample Usage

In the controller:

$scope.filteredCompanies = $filter("goodRatingsOnly")($scope.companies, $scope.issues); 

Or on ng-repeat in the view:

ng-repeat="comp in companies | goodRatingsOnly: issues"

Demo

CodePen: Using an array to filter another array in a custom filter

i managed to solve it this way as well.
not sure how ideal of a solution it may be.

app.filter('issue', function($filter) {

  return function(list, filterList) {

    nullify();

    return $filter("filter")(list, function(listItem){
      if (listItem.ratings_ordered[0] >= filterList[0].value &&
          listItem.ratings_ordered[1] >= filterList[1].value &&
          listItem.ratings_ordered[2] >= filterList[2].value &&
          listItem.ratings_ordered[3] >= filterList[3].value &&
          listItem.ratings_ordered[4] >= filterList[4].value &&
          listItem.ratings_ordered[5] >= filterList[5].value &&
          listItem.ratings_ordered[6] >= filterList[6].value &&
          listItem.ratings_ordered[7] >= filterList[7].value &&
          listItem.ratings_ordered[8] >= filterList[8].value &&
          listItem.ratings_ordered[9] >= filterList[9].value &&
          listItem.ratings_ordered[10] >= filterList[10].value &&
          listItem.ratings_ordered[11] >= filterList[11].value
      ) {
        return listItem;
      }
   });

   function nullify() {
     filterList.forEach(function(issue) {
       if (!issue.selected) {
         issue.value = null;
       }
     });
   }

  }
});

where list = $scope.companies and filterList = $scope.issues.

Related