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

##流れ

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

##⑴ルーティングなど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
#＠ｕｓｅｒｓを配列形式にし、変数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();

//検索に一致するユーザーが０じゃない場合(いる場合)
        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
                削除

```