東日本橋の制作・開発会社 プレスマンのスタッフブログ

PRESSMAN*Tech

プログラミング

typeahead.jsを使ってオートコンプリートを実装する。

オートコンプリートを実現するライブラリとして以前より使用していた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

この記事をシェアする:

-プログラミング
-

Copyright© PRESSMAN*Tech , 2020 All Rights Reserved Powered by STINGER.