AngularJS ng-modelとfilterで複数のkeyにフィルター対応

AngularJS ng-modelとfilterで複数のkeyにフィルター対応

ng-modelとfilter

AngularJSではng-modelとfilterを使用することで簡単にフォームに入力した文字列の絞込ができる。

例えばフォームに入力した文字列で絞込を行いたい場合は下記のようにする。

<input type="text" ng-model="query">
<ul>
  <li ng-repeat="item in items | filter:query">
  {{item.name}} {{item.codename}} {{item.area}}
  </li>
</ul>

厳格な一致

:trueを付けると英字の大文字・小文字を区別して、すべての文字列が一致したもののみが表示される。

<input type="text" ng-model="query">
<ul>
  <li ng-repeat="item in items | filter:query:true">
  {{item.name}} {{item.codename}} {{item.area}}
  </li>
</ul>

特定の項目のみ一致

特定の項目のみの一致に対応したい場合はquery.nameのようにkeyをうしろに付ける。

<input type="text" ng-model="query.name">
<ul>
  <li ng-repeat="item in items | filter:query:true">
  {{item.name}} {{item.codename}} {{item.area}}
  </li>
</ul>

複数のkeyに対応する

ではquery.nameとquery.codenameの絞込を行い、query.areaは検出されないようにするにはどうすればよいか。

私は最初は下記のようにng-modelに複数指定すればよいのかと思ったがng-modelはひとつしか指定できない仕様になっているためこのような指定はできない。

<input type="text" ng-model="(query.name || query.codename)">
<ul>
  <li ng-repeat="item in items | filter:query">
  {{item.name}} {{item.codename}} {{item.area}}
  </li>
</ul>

複数のkeyに対応したfilterを作成

Angularに最初からある標準のfilterは複数のkeyに対応できないため自分で作成する必要がある。

作り方はapp.filterを使用してフィルター名を入力後、引数にdata, queryのように指定して受け取り、queryの文字列がdataのkeyに含まれているかindexOfで調べて含まれているデータを返すだけだ。

var app = angular.module('app', []);
app.controller('Ctrl', ['$scope', function($scope) {
  $scope.items = [
    {'name': 'sato', 'codename': 'foo', 'area': 'tokyo'},
    {'name': 'suzuki', 'codename': 'bar', 'area': 'tiba'},
    {'name': 'tiba', 'codename': 'baz', 'area': 'saitama'}
  ];
}]);
app.filter('filterMultiple', [function() {
  return function (data, query) {
    if (query === undefined) return data;
    var results = [];
    angular.forEach(data, function(val) {
      if ((val.name).indexOf(query) > -1 || (val.codename).indexOf(query) > -1) {
        results.push(val);
      }
    });
    return results;
  }
}]);
<div ng-controller="Ctrl">
  <h1>AngularJS multiple ng-model filter</h1>
  <p>You can search <b>name</b> 'tiba', but <b>area</b> 'tiba' can not search.</p>
  <p><input type="text" ng-model="query"></p>
  <table class="table table-striped table-bordered">
    <tr>
      <th>name</th>
      <th>codename</th>
      <th>area</th>
    </tr>
    <tr ng-repeat="item in items | filterMultiple:query">
      <td>{{item.name}}</td>
      <td>{{item.codename}}</td>
      <td>{{item.area}}</td>
    </tr>
  </table>
</div>

ng-modelのfilterで複数のkeyにフィルター対応サンプル