【Laravel】ajaxを使った検索機能の実装

# 非同期通信で検索機能を実装する

### 簡単な流れ
検索ボタンを押す→サーバー側の任意のアクションへリクエストを投げる→DBから任意の値をとってくる→レスポンスとしてjsonデータをフロント側に返す→フロントはそれを元にビューを作成

###  使用したもの
- user.js
- UserController.php
- user/index.blade.php
- web.php


## step1 フロント側
### 1. イベントの起点を決める

検索フォームとクリックイベントの起点となるボタンを記述

index.blade.php

```
    <div class="search-wrapper col-sm-4">
      <div class="user-search-form">
        {{ Form::text('search_name', null, ['id' => 'search_name', 'class' => 'form-control shadow', 'placeholder' => 'ユーザーを検索する']) }}
        {{ Form::button('<i class="fa fa-search" aria-hidden="true"></i>', ['class' => 'btn search-icon', 'type' => 'button']) }}
      </div>
    </div>

```

### ポイント
- フォームファサードを使うが`Form::open`の記述はいらない
- buttonタグのtypeは`button`にしないと遷移が走ってしまう
- `search-icon`がイベントの起点

### 2.ajaxを走らせる

検索ボタンを押下後にサーバーサイドにリクエストを送れるようにする

```
 $('.user-search-form .search-icon').on('click', function () {
        $('.user-table tbody').empty(); //もともとある要素を空にする
        $('.search-null').remove(); //検索結果が0のときのテキストを消す

        let userName = $('#search_name').val(); //検索ワードを取得

        if (!userName) {
            return false;
        } //ガード節で検索ワードが空の時、ここで処理を止めて何もビューに出さない

        $.ajax({
            type: 'GET',
            url: '/user/index/' + userName, //後述するweb.phpのURLと同じ形にする
            data: {
                'search_name': userName, //ここはサーバーに贈りたい情報。今回は検索ファームのバリューを送りたい。
            },
            dataType: 'json', //json形式で受け取る

            beforeSend: function () {
                $('.loading').removeClass('display-none');
            } //通信中の処理をここで記載。今回はぐるぐるさせるためにcssでスタイルを消す。
         }).done(function (data) {
         //以下は後述

```

### ポイント
- dataTypeはjson
- 今回は表示させるだけなのでget通信
- beforeSendは無くても良い

これでサーバーへ非同期でデータが渡せる

## step2 サーバー側

### 1.コントローラーを呼ぶ

まず、ajaxでurlを設定した通りにweb.phpでルーティングを構築する

```
Route::get('/user/index/{name}', 'UserController@getUsersBySearchName'); // url: '/user/index/' + userNameと同じ
```

これでajaxが走ったときにUserコントローラーの`getUsersBySearchNameアクション`が呼ばれる

### 2.DBから値を取得しjsonでフロントへ返却

URLのパラメーターを引数にUserモデルから任意の値を取得する

UserController.php

```
    public function getUsersBySearchName($userName)
    {
        $users = $this->user->where('name', 'like', '%' . $userName . '%')->withCount('items')->orderBy('items_count', 'desc')->get(); //出品数もほしいため、withCountでitemテーブルのレコード数も取得
        return response()->json($users);
    }

```

### ポイント
- 返り値は必ずjsonデータ

## step3 フロント側
### 1.サーバーから受け取った値をビューに表示

ajax通信が成功したときの処理としてjsonデータをビューに表示させる。
dataにはサーバーから受け取った値がjson形式で入っている

```
}).done(function (data) { //ajaxが成功したときの処理
            $('.loading').addClass('display-none'); //通信中のぐるぐるを消す
            let html = '';
            $.each(data, function (index, value) { //dataの中身からvalueを取り出す
　　　　//ここの記述はリファクタ可能
                let id = value.id;
                let name = value.name;
                let avatar = value.avatar;
                let itemsCount = value.items_count;
　　　　// １ユーザー情報のビューテンプレートを作成
                html = `
                            <tr class="user-list">
                                <td class="col-xs-2"><img src="${avatar}" class="rounded-circle user-avatar"></td> //${}で変数展開
                                <td class="col-xs-3">${name}</td>
                                <td class="col-xs-2">${itemsCount}</td>
                                <td class="col-xs-5"><a class="btn btn-info" href="/user/${id}">詳細</a></td>
                            </tr>
                                `
            })
            $('.user-table tbody').append(html); //できあがったテンプレートをビューに追加
　　　// 検索結果がなかったときの処理
            if (data.length === 0) {
                $('.user-index-wrapper').after('<p class="text-center mt-5 search-null">ユーザーが見つかりません</p>');
            }

        }).fail(function () {
　　　//ajax通信がエラーのときの処理
            console.log('どんまい！');
        })
```

### ポイント
- console.log(data)でdataの中身を確認する
- 検証ツールのnetwork欄でajaxの情報が確認できる
- ドット記法でdataの中身を取り出せる
- eachを使って各テンプレートに変数を代入する
- それをビューにappendさせる（ちなみに上記コードよりまとめたあとに一つの変数としてappendしたほうがよい）

ちゃんとビューに表示されていれば完成！


## 参考資料
-  [LaravelのPaginateをAPIで使う](https://qiita.com/zaburo/items/3104bde70b8eb70d3f09) 
-  [LaravelでAjaxを使う方法。サーバにPOSTしてResponseを返す](https://mintaku-blog.net/laravel-ajax/) 
-  [Laravel と Ajax で値の受け渡して非同期処理。WEBページの更新無しで表示内容の取得が可能](https://niwacan.com/1619-laravel-ajax/)