Search code examples
angularjsangularjs-scopeng-optionsangular-filters

AngularJS - ng-options not returning all matching data after using unique filter


I have a simple set of ng-options. Each child ng-options is supposed to narrow down its data based on the parent being populated.

However, for repeating the main parent - 'Country' i introduced the unique filter as it was repeating items, for example without the filter UK was present twice in the drop down.

However, after selecting UK, i would expect to see London and Leeds in the Cities dropdown, however only London is present.

HTML:

<label>Country</label>
  <select ng-model="country" ng-options="country as country.Country for country in Data | unique:'Country'">
    <option value="">--Countries--</option>
  </select>
<br>
  <label>City</label>
  <select ng-model="city" ng-options="city as city.City for city in Data | filter:country">
    <option value="">--Cities--</option>
  </select>
<br>
  <label>Job Category</label>
  <select ng-model="category" ng-options="category as category.Category for category in Data | filter:city">
    <option value="">--Job Category--</option>
  </select>

JS:

app.controller('MainCtrl', function($scope) {
  $scope.name = 'World';

  $scope.Data = [{
    "Country": "UK",
    "City": "London",
    "Department": "Finance",
    "rank": "2"
  }, {
    "Country": "UK",
    "City": "Leeds",
    "Department": "IT",
    "rank": "3"
  }, {
    "Country": "USA",
    "City": "Texas",
    "Department": "Risk",
    "rank": "5"
  }];

});

app.filter('unique', function() {

  return function(items, filterOn) {

    if (filterOn === false) {
      return items;
    }

    if ((filterOn || angular.isUndefined(filterOn)) && angular.isArray(items)) {
      var hashCheck = {}, newItems = [];

      var extractValueToCompare = function(item) {
        if (angular.isObject(item) && angular.isString(filterOn)) {
          return item[filterOn];
        } else {
          return item;
        }
      };

      angular.forEach(items, function(item) {
        var valueToCheck, isDuplicate = false;

        for (var i = 0; i < newItems.length; i++) {
          if (angular.equals(extractValueToCompare(newItems[i]), extractValueToCompare(item))) {
            isDuplicate = true;
            break;
          }
        }
        if (!isDuplicate) {
          newItems.push(item);
        }

      });
      items = newItems;
    }
    return items;
  };
});

Here's my plunkr: http://plnkr.co/edit/wPCex3lJc5E0I4fSeXI1?p=preview


Solution

  • The problem is not with the unique filter but with the value in $scope.country. It's not a string containing the country but the object that contains the country e.g.

    {
        "Country": "UK",
        "City": "London",
        "Department": "Finance",
        "rank": "2"
    } 
    

    If you change the filter on the city to 'country.Country' then it will work.

    Even better would be to rename country in the expression "country as country.Country for country in Data | unique:'Country'" to something like "item as country.Country for country in Data | unique:'Country'" and use item.Country in the city filter.