Chris92 Chris92 - 3 months ago 45
AngularJS Question

AngularJS filter array of objects, including nested array, with value from <input>

I have such array of objects:

var cars = [
{
"carMake":"Audi",
"models":[
"A4",
"A6",
"R8"
]
},
{
"carMake":"BMW",
"models":[
"3er",
"X3",
"i8",
"7er"
]
},
{
"carMake":"Toyota",
"models":[
"Corolla",
"Auris",
"Yaris",
"Gt86",
"Rav4"
]
}
];


And I have tried below AngularJS code for searching:

$scope.searching = '';
$scope.producers = [];
$scope.models = [];

$scope.searchCar = function() {
$scope.producers = $filter('filter')(cars, function(value) {
return value.carMake === $scope.searching;
});
$scope.models = $filter('filter')(cars, function(value) {
return angular.forEach(value.models, function(model) {
return model === $scope.searching;
});
});
};


Inside HTML I have:

<label>What do you want to find?
<input type="text" ng-model="searching" ng-change="searchCar()" placeholder="Search...">
</label>
<ul>
<li ng-repeat="producer in producers">{{producer}}</li>
</ul>
<ul>
<li ng-repeat="model in models">{{model}}</li>
</ul>


My code doesn't work as I expected - it only outputs whole
cars
Array element. For example, when I type "Audi" i got whole "Audi object", although I want separately results for car producers and/or car models that match pattern inside
<input>
.

I want searching to work like, when I type "Au" then I will see "Audi" in first list and "Auris" in the second. So searching should work as well for
cars.carMake
as for
cars.models[]
and present result in both lists (first/left for car producers and second/right for car models).

Answer

I'd suggest you to store the items in separated arrays, then use the filter in view:

(function() {
  angular
    .module("app", [])
    .controller('MainCtrl', MainCtrl);

  MainCtrl.$inject = ['$scope'];

  function MainCtrl($scope) {
    $scope.sensitiveCompare = sensitiveCompare;
    var cars = [  
       {  
          "carMake":"Audi",
          "models":[  
             "A4",
             "A6",
             "R8"
          ]
       },
       {  
          "carMake":"BMW",
          "models":[  
             "3er",
             "X3",
             "i8",
             "7er"
          ]
       },
       {  
          "carMake":"Toyota",
          "models":[  
             "Corolla",
             "Auris",
             "Yaris",
             "Gt86",
             "Rav4"
          ]
       }
    ];

    $scope.producers = cars.map(function(car) {
      return car.carMake;
    });

    $scope.models = [];
    
    cars.forEach(function(car) {
      $scope.models = $scope.models.concat(car.models);
    });


    function sensitiveCompare(input, search) {
      return ('' + input).indexOf('' + search) > -1;
    }
  }
})();
<!DOCTYPE html>
<html ng-app="app">

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
</head>

<body ng-controller="MainCtrl">
  <label>What do you want to find?
    <input type="text" ng-model="searching" ng-change="searchCar()" placeholder="Search...">
  </label>
  <ul>
    <li ng-repeat="producer in producers | filter: searching: sensitiveCompare" ng-bind="producer"></li>
  </ul>
  <ul>
    <li ng-repeat="model in models | filter: searching: sensitiveCompare" ng-bind="model"></li>
  </ul>
</body>

</html>

EDIT:

If you really want to create your custom function for this, check this:

(function() {
  angular
    .module("app", [])
    .controller('MainCtrl', MainCtrl);

  MainCtrl.$inject = ['$scope', '$filter'];

  function MainCtrl($scope, $filter) {
    $scope.searchCar = searchCar;
    var cars = [  
       {  
          "carMake":"Audi",
          "models":[  
             "A4",
             "A6",
             "R8"
          ]
       },
       {  
          "carMake":"BMW",
          "models":[  
             "3er",
             "X3",
             "i8",
             "7er"
          ]
       },
       {  
          "carMake":"Toyota",
          "models":[  
             "Corolla",
             "Auris",
             "Yaris",
             "Gt86",
             "Rav4"
          ]
       }
    ];
    
    $scope.producers = [];
    $scope.models = [];
    
    function searchCar() {
      $scope.producers = $filter('filter')(cars, function(car) {
        return car.carMake.indexOf($scope.searching) !== -1;
      });
      
      $filter('filter')(cars, function(car) {
        $scope.models = car.models.filter(function(model) {
          return model.indexOf($scope.searching) !== -1;
        })
      });
    }
  }
})();
<!DOCTYPE html>
<html ng-app="app">

<head>
  <script src="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.5.8/angular.min.js"></script>
  <link rel="stylesheet" href="style.css">
  <script src="script.js"></script>
</head>

<body ng-controller="MainCtrl">
  <label>What do you want to find?
    <input type="text" ng-model="searching" ng-change="searchCar()" placeholder="Search...">
  </label>
  <ul>
    <li ng-repeat="producer in producers" ng-bind="producer.carMake"></li>
  </ul>
  <ul>
    <li ng-repeat="model in models" ng-bind="model"></li>
  </ul>
</body>

</html>

Comments