AngularJSのFilterを自作して、 AND検索(スペース区切りで複数ワード検索) を実装してみる。
まず、既存のFilterを用いた絞り込みをつくる
Service
各種メソッドを実装する。
今回は、フィルタをかける対象データを作成する getData() を生成する。
service.js
/**
* コンストラクタ
*/
function SearchService() {
}
/**
* データを返す
*/
SearchService.prototype.getData = function () {
return [
{
id: 1,
name: "空条承太郎",
kana: "クウジョウジョウタロウ",
note: "オラオラ"
},
{
id: 2,
name: "東方仗助",
kana: "ヒガシカタジョウスケ",
note: "変な髪型"
},
{
id: 3,
name: "荒木飛呂彦",
kana: "アラキヒロヒコ",
note: "歳を取らない"
},
{
id: 4,
name: "虹村億泰",
kana: "ニジムラオクヤス",
note: "東方仗助が岸辺露伴を困らせた時わたしは焼身自殺します"
},
{
id: 5,
name: "岸辺露伴",
kana: "キシベロハン",
note: "岸部露伴は動かない"
},
{
id: 6,
name: "広瀬康一",
kana: "ヒロセコウイチ",
note: "エコーズ"
}
];
};
Controller
htmlにデータを渡す機能を担う。
controller.js
function SearchController($scope, searchService) {
$scope.users = searchService.getData();
}
moduleに登録
作成したServiceとControllerをmoduleに登録する。
moduleは、Webアプリケーションでいうインスタンス化やアプリケーションの起動などを行うMain部分。
moduleの第一引数には、後述のng-app属性に指定している文字列を指定する。
main.js
angular.module("SearchApp", [])
.service("searchService", SearchService)
.controller("searchController", SearchController);
データ表示部分
ng-appに任意のアプリケーション名を指定。
これをしていしないとangularアプリケーションは動かないので注意。
index.html(head)
// 忘れずに指定
<html ng-app="SearchApp">
// 関連ファイルを読み込む
<script type="text/javascript" src="js/service/service.js"></script>
<script type="text/javascript" src="js/controller/controller.js"></script>
<script type="text/javascript" src="js/main.js"></script>
index.html(body)
// 文字入力部分
<input type="text" ng-model="keyword" placeholder="Keyword" />
// 表示部分
<div ng-controller="SearchController">
<table class="data-table">
<thead>
<tr>
<th>ID</th>
<th>氏名</th>
<th>フリガナ</th>
<th>備考</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="user in users | filter:keyword">
<td>{{user.id}}</td>
<td>{{user.name}}</td>
<td>{{user.kana}}</td>
<td>{{user.note}}</td>
</tr>
</tbody>
</table>
<div>
ここまでのデモはこちら
AND検索をつくる
オブジェクト探索
入力された文字列を解析するメソッドを追加する。
オブジェクト内に指定したキーワードに一致するものがあるかどうか判定する。
service.js
/**
* オブジェクト内の値がキーワードと部分一致するかどうか判定
* @param obj 検索対象オブジェクト
* @param keyword キーワード配列
* @returns {boolean}
*/
SearchService.prototype.keywordJudge = function (obj, keyword) {
var self = this;
if (angular.isArray(obj)) {
// 配列の場合
// 格納されている要素を順番にチェックし、ひとつでも部分一致した場合trueを返す
return obj.some(function (child) {
return self.keywordJudge(child, keyword);
});
} else if (angular.isObject(obj)) {
// オブジェクトの場合
// 子要素を順番にチェックし、ひとつでも部分一致した場合trueを返す
var properties = Object.getOwnPropertyNames(obj);
return properties.some(function (property) {
var child = obj[property];
return self.keywordJudge(child, keyword);
});
} else if (obj != null) {
// オブジェクト、配列以外で、値がある場合
// 文字列に変換し、部分一致した場合trueを返す
return angular.toJson(obj).search(keyword) != -1;
}
// nullまたはundefinedの場合
return false;
};
CustomFilterをつくる
ANDSearchFilter.js
/**
* AND検索用のFilter
* @param searchService
* @returns {Function} Filterをかけたデータの配列
*/
function ANDSearchFilter(searchService) {
return function (list, searchQuery) {
if (searchQuery) {
// 全角スペースを半角スペースに置換
var query = searchQuery.replace(/ /g, " ");
}
// 検索フォームに文字が入力されている場合
if (query) {
// 検索対象ワードの配列を作成
var queryWordArray = query.split(" ");
var filteredList = [];
list.forEach(function (obj) {
// 検索キーワードでオブジェクトそれぞれを探索
var isMatch = !queryWordArray.some(function (keyword) {
return !searchService.keywordJudge(obj, keyword);
});
// 検索キーワードがAND一致した場合、一覧に表示する配列に格納
if (isMatch) {
filteredList.push(obj);
}
});
return filteredList;
}
return list;
};
}
Filterを登録
作成したフィルタを登録。
index.html(head)
<script type="text/javascript" src="js/filter/andSearchFilter.js"></script>
main.js
angular.module("SearchApp", [])
.service("searchService", SearchService)
.filter("andSearchFilter", ANDSearchFilter)
.controller("searchController", SearchController);
データ表示部分を修正
元々 filter としていた部分を andSearchFilter に置き換える。
index.html
<tr ng-repeat="user in users | andSearchFilter:keyword">