##インクリメンタルサーチ?
簡単に言うと検索できるようにするってことで、目次に沿って早速始めます!
※完全に自分のアウトプット用なので不明瞭な部分があればすいません!
###目次
- ルーティングなどAPI側の準備
- イベントの設定
- イベント時に非同期通信
- 非同期通信の結果を得て、HTMLを作成
- 作成したHTMLをビュー上に追加
###1. ルーティングなどAPI側の準備
Rails.application.routes.draw do
devise_for :users
root 'groups#index'
resources :users, only: [:index, :edit, :update] ←index追加
resources :groups, only: [:new, :create, :edit, :update] do
resources :messages, only: [:index, :create]
end
end
def index
respond_to do |format|
format.html
format.json
end
end
これでサーバーはJSON形式で値を返し、jbuilderファイルが読み込まれるようになる
次にファイルを作成
app
└ views
├ users
│ ├ edit.html.haml
│ └ index.json.jbuilder ←作成 ※indexはアクション名
│
index.json.jbuilder
の中身を以下のように記述
json.array! @users do |user|
json.id user.id
json.name user.name
end
###2. イベントの設定
$(function() {
$('#UserSearch__field').on('keyup',function() {
let input = $('#UserSearch__field').val();
})
})
keyup → 入力するためにキーが押された後、上がるタイミングで処理が実行される
val()で$('#UserSearch__field')の情報を取得
###3. イベント時に非同期通信
$(function() {
$('#UserSearch__field').on('keyup',function() {
let input = $('#UserSearch__field').val();
// ↓↓↓↓↓ ここから追記 ↓↓↓↓↓
$.ajax({
url: '/users',
data: { keyword: input }
type: 'GET',
dataType: 'json',
})
.done(function(users) {
})
.fail(function() {
})
})
まず、data: { keyword: input }のkeywordについて
これは正直なんでもよくて、hogeでもappleでも。
検索、特にkeyupに関することなのでkeywordとしました。
続いてinputは3行目の変数inputのこと。
def index
return nil if params[:keyword] == ""
@users = User.where(['name LIKE ?', "%#{params[:keyword]}%"]).where.not(id: current_user.id).limit(10)
respond_to do |format|
format.html
format.json
end
end
ここのストロングパラメータのkeywordに関しては、
users.js
でkeywordとしているのでそのまま継承
**return nil if params[:keyword] == ""**の意味は
もしkeywordが空の場合はnilをreturnしますよ〜
その下の長いのはあいまい検索のテンプレに値をはめ込んでいけばOK
model名.where('検索するカラム名 LIKE(?)', "検索ワード")
今回は.where.not(不要な情報)
と.limited(数)
をくっつけた感じ。
不要な検索の除外
と、検索件数の取得上限
を設定してます
###4. 非同期通信の結果を得て、HTMLを作成
$(function() {
$('#UserSearch__field').on('keyup',function() {
let input = $('#UserSearch__field').val();
$.ajax({
url: '/users',
data: { keyword: input }
type: 'GET',
dataType: 'json',
})
.done(function(users) {
// ↓↓↓↓↓ ここから追記 ↓↓↓↓↓
$("#UserSearchResult").empty();
if (users.length !== 0) {
users.forEach(function(user) {
addUser(user);
});
} else if (input.length == 0) {
return false;
} else {
addNoUser();
}
// ↑↑↑↑↑ ここまで追記 ↑↑↑↑↑
})
.fail(function() {
})
})
empty()は子要素を削除してるらしいけど、一体何のために?と思って調べてみました
例えばデータベースに下記の名前のユーザーが登録されているとします
tanaka
tamiya
で、検索をかけると"t"を打ち込んだ時点で"tanaka"と"tamiya"がヒットします
"ta"までは2つの検索候補が上がりますが、"tan"まで打ち込むと"tamiya"は削除されます
この動きをさせるためにempty()が必要なんですね〜細かい...
次にこの部分↓
if (users.length !== 0) {
users.forEach(function(user) {
addUser(user);
入力された名前がデータベースに登録してある(0じゃない)とき、
検索にヒットしているユーザーを出しますよ〜
※addUserはあとで使います
そして↓
} else if (input.length == 0) {
return false;
} else {
addNoUser();
}
何も入力していないときはfalseですよ〜
入力してるけどデータベースにはない情報なので addNoUserです〜
という感じ
※addNoUserもあとで使います
###5. 作成したHTMLをビュー上に追加
$(function() {
// ↓↓↓↓↓ ここから追記 ↓↓↓↓↓
function addUser(user) {
let html = `
<div class="ChatMember clearfix">
<p class="ChatMember__name">${user.name}</p>
<div class="ChatMember__add ChatMember__button" data-user-id="${user.id}" data-user-name="${user.name}">追加</div>
</div>
`;
$('#UserSearchResult').append(html);
}
function addNoUser() {
let html = `
<div class="ChatMember clearfix">
<p class="ChatMember__name">ユーザーが見つかりません</p>
</div>
`;
$('#UserSearchResult').append(html);
}
// ↑↑↑↑↑ ここまで追記 ↑↑↑↑↑
$("#UserSearch__field").on("keyup", function() {
let input = $("#UserSearch__field").val();
// 以下省略
addUser
とaddNoUser
をメソッドとして使用。
それぞれの範囲内でappendしてさっきの条件分岐で描画されるようになってます。
htmlの部分は検証ツールで該当するDOMをコピーしてきたら良いかな。
※html3行目に関してはオリジナルで追記する必要あり
一応これでインクリメンタルサーチの実装は完了です。
が!!!!!!!!!!!
検索でヒットしたユーザーを追加したり削除したり、
最終的にそれをデータベースに保存できるようにしたりしないといけないのです...
この後もやること盛りだくさん。
でも『インクリメンタルサーチの実装』なので今回はこの辺で、、
続きはまた次回につなげていきたいと思います。
ここまで読んでいただきありがとうございます。
ご意見、アドバイス等、なんでもお待ちしております。