Laravelで非同期チャットアプリを作ろう（２）

# はじめに
この記事では、片方がコメントを送信したら、もう片方の人はリロードしなくても、コメントが表示されるチャットアプリを作っていきたいと思います。

前回：[Laravelで非同期チャットアプリを作ろう（１）](https://qiita.com/Alesion30/items/8580a85a09822b067ff9)

# 完成物

![chat2.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/fecc0df8-a5d8-68c0-0afd-a30d6a63a946.gif)

ソースコード：https://github.com/Alesion30/ChatApp

# 非同期通信とは

非同期通信とは、ネットワークなどでつながれているコンピュータ間で、送信者のデータ送信タイミングと受信者のデータ受信タイミングを合わせずに通信を行う通信方式のこと。

参照： [非同期通信 － ＠IT リッチクライアント用語事典](https://www.atmarkit.co.jp/aig/07wcr/hidouki.html)

日常生活の例でいうとこんな感じ。

### 同期通信

<img width="875" alt="スクリーンショット 2020-01-22 17.47.07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/99089ef3-e00e-a6f7-3b5d-707fdfc6ae31.png">

### 非同期通信

<img width="930" alt="スクリーンショット 2020-01-22 17.47.26.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/7f142166-a365-945e-b6f7-d3d1b4b627fd.png">

同期通信の場合は、リクエストを送信したらリロードが入り、他の処理を受け付けなくなるが、非同期通信の場合は、リクエストを送信しても、リロードが入らず別の処理を送信することもできる。

# 方針

- APIを作る。（URLにアクセスしたら、jsonデータを返すやつ）
- JavaScriptで、APIを叩きjsonデータを取得する。
- ループ処理を用いてjsonデータを、bladeファイルに埋め込む。

# APIを作る

**HomeController.php**にjsonを返すgetData()という関数を定義する。

```app/Http/Controllers/HomeController.php
public function getData()
{
    $comments = Comment::orderBy('created_at', 'desc')->get();
    $json = ["comments" => $comments];
    return response()->json($json);
}
```

**web.php**に、getData()を登録する。

```routes/web.php
Route::get('/result/ajax', 'HomeController@getData');
```

http://localhost/ChatApp/public/result/ajax にアクセスすると、jsonデータが返ってくる。

<img width="1133" alt="スクリーンショット 2020-01-22 18.03.40.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/85540441-fdd9-6f5c-3eda-c32a504c7f58.png">

# ajaxを使って、jsonを取得する

ajaxを使えるようにするために、app.blade.phpのheadの部分でスクリプトを読み込む。

```html:resources/views/layouts/app.blade.php
<!-- Scripts -->
<script src="{{ asset('js/app.js') }}" defer></script>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
```

これはajaxの基本形である。dataTypeには、jsonだけでなく、csvやhtmlも指定できる。

```javascript
$.ajax({
    url: "result/ajax/",
    dataType: "json",
    success: data => {
      // 成功時の処理
    },
    error: () => {
      // エラー時の処理
    }
})
```

public/jsフォルダにcomment.jsを新規作成する。5秒ごとに、jsonデータを取得している。

```public/js/comment.js
$(function() {
    get_data();
});

function get_data() {
    $.ajax({
        url: "result/ajax/",
        dataType: "json",
        success: data => {
            console.log(data);
        },
        error: () => {
            alert("ajax Error");
        }
    });

    setTimeout("get_data()", 5000);
}
```

app.blade.phpのbodyタグの一番下に、`@yield('js')`を入れる。

```html:resources/views/layouts/app.blade.php
        <main class="py-4">
            @yield('content')
        </main>
    </div>

    @yield('js')
</body>
```

home.blade.phpの一番下で、comment.jsを読み込む。

```html:resources/views/home.blade.php
@section('js')
<script src="{{ asset('js/comment.js') }}"></script>
@endsection
```

http://localhost/ChatApp/public/home にアクセスして、検証ツールを使うと、5秒ごとにjsonデータが送られてきていることがわかる。

<img width="1382" alt="スクリーンショット 2020-01-22 18.16.23.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/e538750b-c9ae-3b22-5299-40bc18499aeb.png">

comment.jsのsuccessの処理を以下のように書き換えてみる。

```public/js/comment.js
success: data => {
    console.log(data.comments);
    for (var i = 0; i < data.comments.length; i++) {
        console.log(data.comments[i].name);
        console.log(data.comments[i].comment);
    }
},
```

<img width="1382" alt="スクリーンショット 2020-01-22 18.29.17.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/61a9e8b7-e4fe-752d-3a51-c9485b99ee3f.png">


# ループ処理を用いてjsonデータを、bladeファイルに埋め込む。

home.blade.phpでコメントを表示している部分を書き換える。

```html:resources/views/home.blade.php
<div class="chat-container row justify-content-center">
    <div class="chat-area">
        <div class="card">
            <div class="card-header">Comment</div>
            <div class="card-body chat-card">
                <div id="comment-data"></div>
            </div>
        </div>
    </div>
</div>
```

JavaScriptで、`<div id="comment-data"></div>`の中にコメントを埋め込んでいく形になる。

comment.jsのsuccessの処理を以下のように書き換える。

```public/js/comment.js
success: data => {
    $("#comment-data")
        .find(".comment-visible")
        .remove();

    for (var i = 0; i < data.comments.length; i++) {
        var html = `
                    <div class="media comment-visible">
                        <div class="media-body comment-body">
                            <div class="row">
                                <span class="comment-body-user" id="name">${data.comments[i].name}</span>
                                <span class="comment-body-time" id="created_at">${data.comments[i].created_at}</span>
                            </div>
                            <span class="comment-body-content" id="comment">${data.comments[i].comment}</span>
                        </div>
                    </div>
                `;
        
        $("#comment-data").append(html);
    }
},
```

http://localhost/ChatApp/public/home にアクセスして、コメントを追加するとうまく反映している。

<img width="1382" alt="スクリーンショット 2020-01-22 18.32.38.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/519787/c2bba8ba-7f20-c56a-b6f4-6767f5b0fa33.png">