インクリメンタルサーチというやつを実装したよ。
ChatSpaceでは、作ったグループ内に集まったメンバー間でのメッセージのやり取りをするという仕様なわけだけれども。
今回追加したインクリメンタルサーチは、グループ新規作成時とグループ情報編集時に、ユーザーネームを検索するという機能のために実装したよ。
コードの解説に行く前に。
インクリメンタルサーチとは
検索したい単語をすべて入力した上で検索するのではなく、入力のたびごとに即座に候補を表示させる。 逐語検索、逐次検索とも。 (引用 : https://ja.wikipedia.org/wiki/%E3%82%A4%E3%83%B3%E3%82%AF%E3%83%AA%E3%83%A1%E3%83%B3%E3%82%BF%E3%83%AB%E3%82%B5%E3%83%BC%E3%83%81)グーグル検索で「あ」とか打ち込むと、検索候補に「アマゾン」ってできてきたりするじゃないですか。
あれのことです。
今回はイメージしやすくていいですね。
では解説に行きます。
インクリメンタルサーチの実装
1.ルーティングなどのAPIの準備をする
今回はusers#indexを使うためのルーティングを用意します。
/config/routes.rb
Rails.application.routes.draw do
(省略)
resources :users , only:[:index,:edit,:update,:show]
(省略)
# ただindexアクションを追加しただけです。
2.テキストフィールドを作成する
これはファイルによりけりなので、ソースコードを省略します。 ちなみに僕の場合の作業ファイルは下記でした。 app/views/groups/_form.html.haml (同階層のindex.html.hamlからrenderでformを読みだしてます。)3.テキストフィールドに入力されるたびにイベントが発火するようにする
app/assets/javascripts/user.js
$('#user-search-field').on('keyup', function(e){
var input = $("#user-search-field").val();
'#user-search-field'がユーザー検索フォームです。
ここに文字を打ち込むたびに処理が発火します。
2行目は、変数input対して、フォームに入力された値を代入しています。
4.イベント時に非同期通信できるようにする
$('#user-search-field').on('keyup', function(e){
var input = $("#user-search-field").val();
$.ajax({
type: 'GET', // HTTPメソッドはGETで
url: '/users', // /usersのURLに (これによりusersコントローラのindexアクションが起動)
data: { keyword: input}, // keyword: inputを送信する
dataType: 'json' // サーバから値を返す際はjsonである
})
.done(function(users){ // usersにjson形式のuser変数が代入される。複数形なので配列型で入ってくる
if (input.length === 0) { // フォームの文字列長さが0であれば、インクリメンタルサーチ結果を表示しないようにする
$('#user-search-result').empty();
}
else if (input.length !== 0){ // 値が等しくないもしくは型が等しくなければtrueを返す。
$('#user-search-result').empty();
users.forEach(function(user){ // users情報をひとつずつとりだしてuserに代入
appendUser(user)
});
}
else {
$('#user-search-result').empty(); // ユーザーが見つからなければ「見つからない」を返す。
appendErrMsgToHTML("一致するユーザーが見つかりません");
}
})
.fail(function() {
alert('ユーザー検索に失敗しました');
});
});
ちょっと長いので詳細はコメントアウトの記述に譲りますが、流れを解説します。
(※appendUser(user)とappendErrMsgToHTML("一致するユーザーが見つかりません")はメソッドです。後述します。)
keyupにより発火。
ajaxで通信をする。その際のメソッド、リクエストの指定、データの指定、データタイプの指定をしています。
これをコントローラが受け取って、jbuilderの記述に従ってjson形式でJavaScriptに戻ってきます。
(コントローラとjbuilderの記述は冗長になるので省きます。)
done⇨通信が成功した場合は文字列の長さと型(integerかstringか)で判断します。
fail ⇨アラートを出します。
5.非同期通信の値を元に、HTMLに反映します。
$(document).on('turbolinks:load', function(){
var search_list = $("#user-search-result");
var member_list = $("#member-append");
function appendUser(user){
var html =
`<div class="chat-group-user clearfix">
<p class="chat-group-user__name">${user.name}</p>
<div class="user-search-add chat-group-user__btn chat-group-user__btn--add" data-user-id=${user.id} data-user-name=${user.name}>追加</div>
</div>`;
search_list.append(html);
}
function appendErrMsgToHTML(msg){
var html =
`<div class="chat-group-user clearfix">
<p class="chat-group-user__name">${msg}</p>
</div>`;
search_list.append(html);
}
4の際に記述されていた、appendUser(user)とappendErrMsgToHTML("一致するユーザーが見つかりません")のメソッドを定義しています。
()内に記載しているのは引数です。
これでインクリメンタルサーチの大まかな流れは終わりです。
とっかかりは凄くハードルが高く感じますが、一個一個解説していくとそんなに難しくないかなぁと思います。
ポイントはやっぱり$.ajax内部で指定している部分かなと思います。
自動更新機能の実装なんかもしたのですが、ここの設定によるミスで頻繁にエラーが発生しました。。。
明日は自動更新機能も書きたいと思っています。