【Laravel】CRUDで非同期（Ajax）削除処理を作る


# Laravelで削除の非同期処理を実装する条件


1. [jQueryを動かすためのCDN](#jQueryを動かすためのCDN)
1. [POST通信をするためのトークン【とても重要】](#POST通信をするためのトークン【重要】)
1. [HTMLタグから情報を取得するカスタムデータ属性](#HTMLタグから情報を取得するカスタムデータ属性)
1. [コントローラへ非同期通信するためのAjax](#コントローラへ非同期通信するためのAjax)
1. [コントローラーへ移動するルーティング](#コントローラーへ移動するルーティング)
1. [データを受取りレコードを削除するコントローラー](#データを受取りレコードを削除するコントローラー)

![スクリーンショット 2022-11-16 13.17.54.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/e9716611-78f8-c1bc-de46-d0819d265c97.png)
以下の説明では、`非同期で削除するコード`以外は省いています。

## jQueryを動かすためのCDN
非同期処理（ajax通信)を実装するためにはjQueryの`$.ajaxメソッド`が必要です
そのためjQueryを動かすためにCDNをHTMLの`headタグ`に記述します
```html:app.blade.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>@yield('title')</title>

    <!--Bootstrap CSS -->
    {{--<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">--}}
    <link rel="stylesheet" href="{{ asset('css/app.css') }}">

    <!--Font Awesome5-->
    <link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.6.3/css/all.css">
    <script src="https://code.jquery.com/jquery-3.6.1.min.js" integrity="sha256-o88AwQnZB+VDvE9tvIXrMQaPlFFSUTR+nldQm1LuPXQ=" crossorigin="anonymous"></script>
    <meta name="csrf-token" content="{{ csrf_token() }}">
</head>
<body class="d-flex flex-column">

<!-- ヘッダー -->
@include('layouts.header')

<!-- コンテンツ -->
@yield('content')



</body>

<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" ></script>
</body>
</html>

```
### CDNのリンク記述場所に注意
CDNのリンクは、jQueryの処理コード部分よりも
前に記述する必要があります。
後に記述された場合、jQueryが利用できません。
そのため、HTMLのheadタグ内部に記述することが推奨されます。

### CDNでの導入方法
https://code.jquery.com にアクセスし
`jQuery Core 3.*.*`の`minified`をクリック
表示された`script`のコードをコピーしHTMLへ貼り付けします

![スクリーンショット 2022-11-16 13.24.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2765288/08c00126-ae3a-2320-dfbe-4b41b28bd766.png)


## POST通信をするためのトークン【とても重要】
LaravelでPOST通信をするには必ず`トークンを送る`ための記述が必要です
Laravelの仕様でトークンを送らなければエラーが発生し、
通信が失敗、つまりエラーが発生します。

### ajaxでトークンを送信する方法とは？

ajaxのコードを処理を記述するscriptタグへ
非同期処理とセットで以下の記述をすることにより
トークンが送信されます
```HTML:index.blade.php
<script>

// ここからトークン送信処理
$.ajaxSetup({
    headers: {
                'X-CSRF-TOKEN': '{{ csrf_token() }}'
                }
            });

//ここから非同期処理の記述

// $(function() {
//     $.ajax({
//                  type: 'POST'
//                      , url: '/destroy/'+userID
//                      , dataType: 'json'
//                      , data: {'id':userID},
    
    
                

```

ajaxの場合はページを更新しないためエラーコードが出ず
問題には非常に気が付きにくいことが挙げられます




## HTMLタグから情報を取得するカスタムデータ属性
削除の対象になるHTMLタグに`カスタムデータ属性`で

jQuery側にてHTMLの`値`を取得することができます

### カスタムデータ属性とは？
htmlタグに付与できるclass属性やid属性などと同じ利用方法の属性で
かつ、`オリジナルの名前で設定できる属性`です

カスタムデータ属性は、`data-***`で作成します。
***の部分を任意の文字列で設定できます。
他の要素名（class名、ID名など）とは重複できません。

```html:index.blade.php
 <form  class="id">
        <input data-user_id="{{$user->id}}" type="submit" class="btn-dell" value="削除">
 </form>
```

### 削除したいレコードの"ID"をjQueryへ渡すには？

まずはMVCの流れで
コントローラーでモデル（データベース）の情報を取得します

*前提条件*
- Laravelのプロジェクトへすでにモデル、コントローラー、ビューファイルが存在する
- プロジェクトとMySQLなどはすでに紐付けの設定がされている


```php:User.php

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Users extends Model
{
    
}


```
```HomeController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Users;
use Illuminate\Support\Facades\DB;

class HomeController extends Controller
{
     
    public function index(Request $request)
    {
             
        /* テーブルから全てのレコードを取得する */
        $users = Users::query();
        
         /* ページネーション */
        /* レコード数が多い時にページを分割して表示します(今回は5レコードごとにページを分けます） */
        /* 分割の必要がなければ省略しても問題ありません */
        $posts = $users->paginate(5);

        return view('crud.index', ['posts' => $posts]);
        /* ページネーションが必要なければ、postsはusersに置き換えます */
    }

}

```


```html:index.blade.php

@extends('layouts.app')

@section('content')

<div class="wrapper mx-auto" style="padding-top:30px;">



<!--テーブル-->

      <div class="table-responsive">
          <table class="table" style="width: 1000px; max-width: 0 auto;">
                <tr class="table-info">
                <th scope="col" >id</th>
                <th scope="col" >名前</th>
             
                  <th scope="col" >削除</th>
                </tr>

<!--繰り返し処理-->
<!--1レコードずつ情報を表示します-->
 @foreach($posts as $user)  
<tr>
 
         <td>{{$user->id}}</td>
         <td>{{$user->name}}</td>

<!-- blade.php内で変数を利用するためには前後を　{{ }} で囲む必要があります　-->　　　　　　　　　　　　

<!--削除に必要なボタン要素-->
  <td>  
    <form  class="id">
        <input data-user_id="{{$companie->id}}" type="submit" class="btn btn-danger btn-dell" value="削除">
      </form>
  </td>

</tr>
@endforeach

         </table>
       </div>
    <!--ページネーションを表示する変数-->
       {{ $posts->links() }}

    </div>

```




## コントローラへ非同期通信するためのAjax
```javascript:index.blade.php

<script type="text/javascript">

// トークンを送信する記述
// Laravelでは通信をする際にトークンを送らなければ仕様でエラーが発生する
$.ajaxSetup({
    headers: {
        'X-CSRF-TOKEN': '{{ csrf_token() }}'
    }
});


// ここから非同期処理の記述
$(function() {
                
 //削除ボタンに"btn-danger"クラスを設定しているため、ボタンが押された場合に開始されます
              $('.btn-danger').on('click', function() {
                var deleteConfirm = confirm('削除してよろしいでしょうか？');
//　メッセージをOKした時（true)の場合、次に進みます 
                    if(deleteConfirm == true) {
                      var clickEle = $(this)
//$(this)は自身（今回は押されたボタンのinputタグ)を参照します
//　"clickEle"に対して、inputタグの設定が全て代入されます

                      var userID = clickEle.attr('data-user_id');
 //attr()」は、HTML要素の属性を取得したり設定することができるメソッドです
 //今回はinputタグの"data-user_id"という属性の値を取得します
 //"data-user_id"にはレコードの"id"が設定されているので
 // 削除するレコードを指定するためのidの値をここで取得します

 // .ajaxメソッドでルーティングを通じて、コントローラへ非同期通信を行います。
//見本ではレコードを削除するコントローラへ通信を送るためにはweb.phpを参照すると
//通信方法は"post"に設定し、URL（送信先）を'/destroy/{id}'にする必要があります
                         
              $.ajax({
                 type: 'POST',
                 url: '/destroy/'+userID, //userID にはレコードのIDが代入されています
                 dataType: 'json',
                 data: {'id':userID},
                          })
//”削除しても良いですか”のメッセージで”いいえ”を選択すると次に進み処理がキャンセルされます
            } else {
                    (function(e) {
                      e.preventDefault()
                    });
            };
      });
});
//.ajaxメソッドではオプション（引数）を設定することで送信先（URL)や送信する変数を指定できます
//type は　通信方式をGETもしくはPOSTから選択できます（デフォルトはGETです）
//urlは送信先（URL)を指定します。ルーティングで設定しているURLになるよう文字列と変数を記述します
//dataType はjavascriptからこれから送るデータの種類は何であるかを示します
//json とは "JavaScript Object Notationの略"
//json は javascriptのほかphpや多数の言語でも読み取れるフォーマットなので設定しておけばエラーが出ません

//data はURL先（コントローラー）に渡す値です。今回は削除したいレコードの”id”を渡します。
//dataの書き方は   
//data:{'コントローラーのアクションで使う引数':jQueryから渡す変数}になります
</script>

```
## コントローラーへ移動するルーティング

ajaxで指定するURLはルーティングを参照します。
レコードを削除するコントローラーのアクションにつながるURLは
`post`の`/destroy/{id}`となっているため、ajaxメソッドでの送信先は
`/destroy/` + （idの値が代入されている）変数となります

```php:web.php

Auth::routes();

Route::get('/', 'HomeController@index')->name('crud.index'); /* 一覧表示 */

Route::post('/destroy/{id}', 'HomeController@destroy'); /* レコード削除 */
```

## データを受取りレコードを削除するコントローラー


```php:HomeController.php
public function destroy(Request $request, Users $users) {

//ajaxメソッドから送信されたデータは$requestに格納されます
//ajas側で送信したデータの名前は"id"という名前に設定しているため
//コントローラーで使うには $request->id で出力します
     
            $users = Users::findOrFail($request->id);
//データベースのUsersテーブルから()で指定されたiDのレコードを代入します
            $users->delete();
//usersに代入されているレコード（行）を削除します

    }
```