David Gard
David Gard

Reputation: 12047

Filter an array by two different criteria

I have the below code which uses a controller to grab the contents of a JSON file and then display the first 5 results. The code also includes a filter to allow users to search.

The filter looks for results in both name and code (see below JSON example), which is great. However, I'd like for the filter to do more; code is unique, and if a match to code is found it should be displayed at the top of the list, with the remaining four results listed by name underneath.

For example, if the user was to search for swi, currently the five results that are listed are -

Brunswick (BRW)
Chiswick (CHK)
Derby Road (Ipswich) (DBR)
Giggleswick (GIG)
Hutton Cranswick (HUT)

What I would like is -

Swindon (SWI)
Brunswick (BRW)
Chiswick (CHK)
Derby Road (Ipswich) (DBR)
Giggleswick (GIG)

Is this possible using AngularJS, or would I be looking at using some more complex logic to get my desired results?


JSON example

[
  {
    "name": "Abbey Wood",
    "code": "ABW"
  },
  {
    "name": "Aber",
    "code": "ABE"
  },
  {
    "name": "Abercynon",
    "code": "ACY"
  }
]

My code

<!DOCTYPE html>
<html lang="en-GB" data-ng-app="tigerSelector">
<head>

    <meta charset="UTF-8">
    <title>Tiger | Staff CIS Selector</title>
    
    <!-- Mobile stuff -->
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <meta name="mobile-web-app-capable" content="yes">
    
    <!-- Angular JS -->
    <script src="angular/angular.js"></script>

    <script type="text/javascript">
    
        var app = angular.module('tigerSelector', []);
        
        app.controller('stationsCtrl', function($scope, $http){
            $http.get('stations.json').then(function(res){
                $scope.stations = res.data;                
            });
        });
    
    </script>
    
</head>

<body>

<div data-ng-controller="stationsCtrl">

    <p>Filtering input:</p>

    <p><input type="text" data-ng-model="search"></p>

    <ul>
        <li data-ng-repeat="station in stations | filter:search | orderBy:'name' | limitTo:5">
            {{ station.name }} ({{ (station.code | uppercase) }})
        </li>
    </ul>
    
</div>

</body>
</html>

Upvotes: 1

Views: 79

Answers (1)

Paul Boutes
Paul Boutes

Reputation: 3315

You can create custom filter, and iterate over your collection, and passing your search ngModel to the filter.

Filter

(function(){

  function filter(){
    return function (input, search) {
      var out = [];
      //Map over the input
      [].map.call(input || [], function(elm){
        //Compare code value to search model
         elm.code.toLowerCase() === search
         //Push elm at the beginning of the array
         ? out.unshift(elm)
         //Otherwise, add element to the end of the array
         : out.push(elm);
       });

       //Return our filtered array
       return out;
   };
  }

  angular
    .module('app')
    .filter('myFilter', filter);

})();

Then you can call your filter into your template. You can combine multiple filter.

HTML

<p><input type="text" data-ng-model="search"></p>

<ul>
    <li data-ng-repeat="station in stations | myFilter:search | filter:search | limitTo:5">
        {{ station.name }} ({{ (station.code | uppercase) }})
    </li>
</ul>

Upvotes: 1

Related Questions