オートコンプリートを実現するライブラリとして以前より使用していたtypeaheadですが、日本語の情報が少ないのと、v0.11になったら以前と互換性が無くなってしまったので、調べて記録しておきます。
http://twitter.github.io/typeahead.js/
インストールはbowerを使用して
bower install typeahead.js
でおしまいです。手動でファイルだけをダウンロードしても問題ありません。
typeahead.jsは、BloodhoundとTypeaheadの2つのファイルがあります。
本家のドキュメントでBloodhoundはtypeahead.jsのサジェストエンジン、typeahead.jsはサジェストされた値をレンダリングしたり、DOMのハンドリングをすると書いてありますが、つまり、Bloodhoundが表示するデータを用意して、typeahead.jsがそれを表示するようになっています。
ですので、Bloodhoundはなくても、決まった形にしてtypeahead.jsに渡せばオートコンプリートは実現出来ます。例えば、本家にある最初のサンプル(http://twitter.github.io/typeahead.js/examples)はtypeahead.jsだけを使用しています。
ただ、Bloodhoundは色々な機能があって使わない手はないのですが、ドキュメントが貧弱でソースを読まないとイマイチよくわかりません。
以下はElasticsearchのCompletion Suggesterを使っているリモートサーバーにデータを取りに行くサンプルです。
Completion Suggester: https://www.elastic.co/guide/en/elasticsearch/reference/current/search-suggesters-completion.html
var displayKey = 'text';
var suggester = new Bloodhound({
//データを検索対象の配列にするためのfunction
//多分localで設定したデータにしか使われない。Bloodhound.tokenizersにはwhitespaceとnonwordがある。
//whitespaceは/\s+/で区切り、nonwordは/\W+/で区切っている。
//"abc def"は["abc","def"]の配列になり"ab"でも"de"でも"abc def"がヒットするようになる。
datumTokenizer: Bloodhound.tokenizers.obj.whitespace(displayKey),
//検索キーワードを区切って配列にする。datumTokenizerと同じ。
//これもローカルデータにしか関係無いっぽい。
queryTokenizer: Bloodhound.tokenizers.whitespace,
remote: {
url: 'https://xxx.xxx.xxx/music/_suggest',
prepare: function(query, settings){
//ここでリモートサーバーに渡すクエリを加工できます
//例えば全角数字を半角にしてみる。
query = query.replace(/[0-9]/g, function(s) {
return String.fromCharCode(s.charCodeAt(0) - 0xFEE0);
});
var data = {
"song-suggest" : {
"text" : query,
"completion" : {
"field" : "suggest"
}
}
};
//settingsはjQueryの$.ajaxへ渡すオプション。
settings.type = 'POST';
settings.contentType = 'application/json';
settings.xhrFields = {
withCredentials: false
};
settings.data = JSON.stringify(data);
return settings;
},
transform: function(res){
//ここで返ってきたデータを整形する。
//typeheadに渡すオプションのdisplayに設定したキーを持っているobjectの配列にする。
return res[options.type][0].options;
},
rateLimitWait: 500//検索し出すまでの待機時間 ms
},
//ローカルでデータを持つことも出来る。
//remote.transformと同じでtypeheadに渡すオプションのdisplayに設定したキーを持っているobjectの配列にする。
local:[{text:'a'},{text:'b'},{text:'ab'},{text:'abc def'}]
});
//typehead.jsのほうは比較的ドキュメントがわかりやすい。
//https://github.com/twitter/typeahead.js/blob/master/doc/jquery_typeahead.md
$("#suggest").typeahead({
//オプション
highlight: true,//候補に一致する文字があれば強調表示される。
hint: true, //入力欄にヒント表示をする。
minLength:3, //入力文字数がこの数にならないとサジェストしない。
classNames:{} //Class名を上書きする。詳しくはマニュアル参照
}, {
//データセット
name: 'suggest',// これに{{classNames.dataset}}- (デフォルトだとtt-dataset-)がついてデータセットのDOMのクラス名になる。
display: displayKey,//このキーを使ってデータから表示するデータを取得してくる。
source: suggester//データを作成する関数。Bloodhoundでもいいし、ルールに則っていれば何でもいい。
});
リモートで一度取得したデータはキャッシュされます。
$.ajaxへ渡すパラメータのurl,type,dataを使ってキャッシュのキーを作っています。
詳しくはBloodhoundのソースをfingerprintで検索してみて下さい。
その他表示部分のテンプレートを変更したりも出来ますが機会があれば解説します。
投稿日時点での最新版のv0.11.1ではリモートで取得したデータをサジェストしない不具合があります。
tyepahead.jsで指定した表示件数ーリモートで取得した件数 = 表示件数
になっています。
v0.11.2で修正されるようで既にコミットされています。
https://github.com/twitter/typeahead.js/pull/1200