Search code examples
javascripthtmlangularjsangularjs-filter

Cascading selects AngularJS filter not display data in second time


Considering the code below:

<html ng-app="app">
  <head>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.3/angular.min.js"></script>
  </head>
  <body ng-controller="appCtrl">
    <div class="filters">
      <div>
        Color: <select id="color" ng-model="colorfilter" ng-options="car.color as car.color for car in cars | unique:'color'" ng-change="changeColor()">
        </select>
        Model: <select id="model" ng-disabled="!colorfilter" ng-model="modelfilter" ng-options="car.model as car.model for car in cars | filter:{color:colorfilter} | unique:'model'" ng-change="changeModel()">
        </select>
      </div>
    </div>
    <div class="list">
      <p class="car" ng-repeat="car in cars | filter:colorfilter | filter:modelfilter">{{car.make}} :: {{car.model}} | {{car.color}}</p>
    </div>
  </body>
</html>

And the controller.js:

angular.module('app', [])
.filter('unique', function() {
  return function(input, key) {
    var unique = {};
    var uniqueList = [];
    for(var i = 0; i < input.length; i++){
        if(typeof unique[input[i][key]] == "undefined"){
            unique[input[i][key]] = "";
            uniqueList.push(input[i]);
        }
    }
    return uniqueList;
  };
})
.controller('appCtrl', function($scope) {
// define list of cars
  $scope.cars = [
    {make:"Dodge", color:"Blue", model:"Dakota"},
    {make:"Chevy", color:"Black", model:"Aveo"},
    {make:"Honda", color:"Black", model:"Accord"},
    {make:"Toyota", color:"Red", model:"Corolla"}
    //... other lines
  ];

  // initialize filter object
  $scope.filter = {};

});

The list of cars is displayed complete below the select fields. When I filter at the first time, the first select normally filters both the list of cars (considering the selected color) and the second select data (only models that have the selected color). And the second select also filters the list of cars considering the selected model. That sounds perfect!

However, when I try to perform a new filter, when I choose another color, it does not display any records in the list of cars, but it usually works by filtering the data of the second select. By choosing one of the models available in the second select, the list is displayed, exactly the combination of the two selections (such as an AND of the selects).

It seems that only the list data that is currently being viewed on the screen are considered for the first select, needing to wait for the second select to display the result. But my intend is to display the results to each filter, always searching for the complete list of items.

My full code on Codepen.


Solution

  • I think this may be what you're looking for. Based on your ng-disabled logic, I figured you want the user to always go in the order of selecting color then model.

    https://codepen.io/Cameron64/pen/YZbrqW?editors=1010

    To maintain this order I set the color dropdown to reset when the model dropdown is selected from. Additionally I grouped the filter into one object so that it isn't so verbose when passed to the repeater

    $scope.changeColor = function() {
      $scope.filter.model = undefined;
      $scope.filter.color = $scope.filter.color || undefined;
    }