LoginSignup
27
25

More than 3 years have passed since last update.

chat-spaceインクリメンタルサーチ機能の実装

Posted at

流れ

⑴ルーティングなどAPI側の準備をする
⑵テキストフィールドを作成する
⑶テキストフィールドに入力されるたびにイベントが発火するようにする
⑷イベント時に非同期通信できるようにする
⑸非同期通信の結果を得て、HTMLを作成する
⑹作成したHTMLをビュー上に追加する
⑺エラー時の処理を行う
⑻追加ボタンが押された時にイベントが発火するようにする
⑼追加ボタンをクリックされたユーザーの名前を、チャットメンバーの部分に追加し、検索結果からは消す
⑽削除を押すと、チャットメンバーから削除される
11ログイン中のユーザーを追加済みの状態にする
12編集画面では既存のユーザーが追加済みの状態にする

⑴ルーティングなどAPI側の準備をする

routes.rbでusers#indexのルーティングを設定する。
users_controller.rbにindexアクションを追加する。
JSON形式のレスポンスを返せるようにコントローラーに設定する

users_controllers.rb
def index
#検索した条件に当てはまるユーザーを@usersに代入
  @users = User.search(params[:keyword], current_user.id)

#htmlとjsonで処理を分ける
  respond_to do |format|
    format.html
    format.json
  end
end
index.json.jbuilder
#@usersを配列形式にし、変数userとして分解していく
json.array! @users do |user|
  json.id user.id
  json.name user.name
end

#これにより、jsファイル上で、usersという配列、id、nameという変数が使えるようになる

⑵テキストフィールドを作成する

僕の場合は_form.html.hamlに記載

⑶テキストフィールドに入力されるたびにイベントが発火するようにする

users.js
$(function() {

//検索欄に文字入力されるたびに処理を行う
  $("#user-search-field").on("keyup", function() {

//検索欄に入力された文字をvalで取得し変数inputに代入
      let input = $("#user-search-field").val();
});

⑷イベント時に非同期通信できるようにする

ajaxの処理

users.js

$.ajax({
      type: "GET", //httpメソッド(今回はget)
      url: "/users", //送る先のurl

//keyを自分で決め(今回は"keyword"と定義)valueには先ほど検索欄から取得し代入したinputの値を使う
      data: { keyword: input }, 
      dataType: "json"
    })

//ちゃんと動いているかを確認するために一時的にconsole.log
      .done(function(users) {
        console.log("成功です");
      })

//ちゃんと動いているかを確認するために一時的にconsole.log
      .fail(function() {
        console.log("失敗です");
      });
  });
});

コントローラーの編集

users.controller.rb

def index

#キーワードがなければnilを返す
  return nil if params[:keyword] == ""

#その文字を含むユーザーを探してきて、@usersに代入、ただしログインしている自分は除く。10人まで。
  @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

⑸&⑹非同期通信の結果を得て、HTMLを作成しビュー上に追加する

done関数の処理

users.js


//jbuilderファイルで作った配列を引数にしdone関数を起動
.done(function(users) {

//if,else if,elseどの場合においても、処理後は、すでに検索欄に出力されている情報を削除する。
        $("#user-search-result").empty();

//検索に一致するユーザーが0じゃない場合(いる場合)
        if (users.length !== 0) {

//usersという配列をforEachで分解し、ユーザーごとにaddUser関数に飛ばす(処理は後ほど)
          users.forEach(function(user) {
            addUser(user);
          });

//入力欄に文字が入力されてない場合処理を終了
        } else if (input.length == 0) {
          return false;

//検索に一致するユーザーがいない場合はaddNoUserに飛ばす
        } else {
          addNoUser();
        }
      })

引数に値が入っていた場合とそうじゃない場合のhtmlを生成し、それらをぶち込む

users.js

//一致するユーザーがいた場合の処理
function addUser(user) {
    let 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>
    `;

//作ったhtmlをぶち込む
    $("#user-search-result").append(html);
  }


//一致するユーザーがいなかった場合の処理
  function addNoUser() {
    let html = `
      <div class="chat-group-user clearfix">
        <p class="chat-group-user__name">ユーザーが見つかりません</p>
      </div>
    `;
//作ったhtmlをぶち込む
    $("#user-search-result").append(html);
  }

⑺エラー時の処理を行う

failの処理を記述

users.js

.fail(function() {
        alert("通信エラーです。ユーザーが表示できません。");
      });

⑻、⑼追加ボタンが押された時にクリックされたユーザーの名前を、チャットメンバーの部分に追加し、検索結果からは消す

users.js

//追加ボタンがクリックされた時の処理を記述する
$(document).on("click", ".chat-group-user__btn--add", function() {

//クリックされたところのデータを取得し各変数に代入
    const userName = $(this).attr("data-user-name");
    const userId = $(this).attr("data-user-id");

//クリックされたところのhtmlを親要素をごと消す(検索結果から消す)
    $(this)
      .parent()
      .remove();

//削除ボタンの書いてあるhtmlを呼び出す処理に飛ばす
    addDeleteUser(userName, userId);


//ユーザーをグループに登録するための処理
    addMember(userId);
  });

  });

削除ボタンが押された時の処理

users.js

function addDeleteUser(name, id) {
    let html = `
    <div class="chat-group-user clearfix" id="${id}">
      <p class="chat-group-user__name">${name}</p>
      <div class="user-search-remove chat-group-user__btn chat-group-user__btn--remove js-remove-btn" data-user-id="${id}" data-user-name="${name}">削除</div>
    </div>`;

//作ったhtmlをぶち込む
    $(".js-add-user").append(html);
  }


ユーザーをグループに登録するための処理

users.js

function addMember(userId) {

//userのidをinputタグの初期値としそれをnameを使ってgroupsコントローラ内のparamsで受け取る準備
    let html = `<input value="${userId}" name="group[user_ids][]" type="hidden" id="group_user_ids_${userId}" />`;

//作ったinputタグをaddDeleteUser内で作ったhtml内にぶち込む
    $(`#${userId}`).append(html);
  }

⑽削除を押すと、チャットメンバーから削除される

users.js

$(document).on("click", ".chat-group-user__btn--remove", function() {

//クリックされたところのhtmlを親要素をごと消す(検索結果から消す)
    $(this)
      .parent()
      .remove();
  });

11 ログイン中のユーザーを追加済みの状態にする

_form.html.haml

%input{name: "group[user_ids][]", type: "hidden", value: current_user.id}

//ログインしているユーザーを取得し表示
%p.chat-group-user__name
  = current_user.name

12編集画面では既存のユーザーが追加済みの状態にする

_form.html.haml

//そのグループに属するユーザーの配列をユーザーごとに分解する
- group.users.each do |user|

//もともと自分は表示されているので、それ以外のユーザーを表示
- if current_user.name != user.name
    .chat-group-user.clearfix.js-chat-member
       %input{name: "group[user_ids][]", type: "hidden", value: user.id}
       %p.chat-group-user__name
          = user.name
       %a.user-search-remove.chat-group-user__btn.chat-group-user__btn--remove.js-remove-btn
                削除

27
25
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
27
25