1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

インクリメンタルサーチの実装

Last updated at Posted at 2020-07-17

##インクリメンタルサーチ?
簡単に言うと検索できるようにするってことで、目次に沿って早速始めます!
※完全に自分のアウトプット用なので不明瞭な部分があればすいません!


###目次

  1. ルーティングなどAPI側の準備
  2. イベントの設定
  3. イベント時に非同期通信
  4. 非同期通信の結果を得て、HTMLを作成
  5. 作成したHTMLをビュー上に追加

###1. ルーティングなどAPI側の準備

routes.rb
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
users_controller.rb
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. イベントの設定

users.js
$(function() {
  $('#UserSearch__field').on('keyup',function() {
    let input = $('#UserSearch__field').val();
  })
})

keyup → 入力するためにキーが押された後、上がるタイミングで処理が実行される
val()で$('#UserSearch__field')の情報を取得


###3. イベント時に非同期通信

users.js
$(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のこと。

users_controller.rb
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を作成

users.js
$(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()が必要なんですね〜細かい...

次にこの部分↓

users.js
if (users.length !== 0) {
 users.forEach(function(user) {
   addUser(user);

入力された名前がデータベースに登録してある(0じゃない)とき、
検索にヒットしているユーザーを出しますよ〜
※addUserはあとで使います

そして↓

users.js
} else if (input.length == 0) {
return false;
} else {
  addNoUser();
      }

何も入力していないときはfalseですよ〜
入力してるけどデータベースにはない情報なので addNoUserです〜
という感じ
※addNoUserもあとで使います


###5. 作成したHTMLをビュー上に追加

users.js
$(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();
// 以下省略

addUseraddNoUserをメソッドとして使用。
それぞれの範囲内でappendしてさっきの条件分岐で描画されるようになってます。
htmlの部分は検証ツールで該当するDOMをコピーしてきたら良いかな。
※html3行目に関してはオリジナルで追記する必要あり


一応これでインクリメンタルサーチの実装は完了です。

が!!!!!!!!!!!

検索でヒットしたユーザーを追加したり削除したり、
最終的にそれをデータベースに保存できるようにしたりしないといけないのです...
この後もやること盛りだくさん。

でも『インクリメンタルサーチの実装』なので今回はこの辺で、、
続きはまた次回につなげていきたいと思います。

ここまで読んでいただきありがとうございます。
ご意見、アドバイス等、なんでもお待ちしております。

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?