#7 いいね機能の実装 ~laravel×AWSで掲示板を作ろう~

#laravel×AWSで掲示板を作ろう
本記事は、laravel×AWSの第7回です。
作ったサイト：<https://vible.jp>

#laravel×ajaxでのいいね機能
ajaxとはjavascriptに搭載されている機能の一つで、googlemapのように画面をリロードすることなく処理を実行してくれるものです。
ajaxを使うことでTwitterとかでも見られるようないいね機能が再現できます。
laravelmixを使っています。
![like.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/832092/65287d44-cae0-a785-c26f-dfb388c4e70b.gif)



```php:nayami_blade.php
@extends('layouts.layout')
<!DOCTYPE html>
<html>

<head>
  <title>nayami</title>
  <style>
    body {
      font-size: 16pt;
      color: #999;
    }

    th {
      background-color: #999;
      color: fff;
      padding: 5px 10px;
    }

    td {
      border: solid 1px #aaa;
      color: #999;
      padding: 5px 10px;
    }
  </style>

  <meta name="csrf-token" content="{{ csrf_token() }}">
</head>

@section('content')

<div class="outer">
  <div class="inner1">

    <br>
    <h1>投稿された悩み一覧</h1>
    <br>

    <script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
    <link href="https://use.fontawesome.com/releases/v5.6.1/css/all.css" rel="stylesheet">
  </div>

  <div class="inner2">
    @foreach($questions as $question)
    <div class="tw-block-parent">
      @auth
      @if((int)$question->user_id == Auth::user()->id)
      <div class="button2">
        <button class="btn btn-primary" data-toggle="modal" data-target="#modal-example{{$question->id }}">
          削除
        </button>
        <!-- 2.モーダルの配置 -->
        <div class="modal" id="modal-example{{$question->id }}" tabindex="-1">
          <div class="modal-dialog">
            <!-- 3.モーダルのコンテンツ -->
            <div class="modal-content">
              <!-- 4.モーダルのヘッダ -->
              <div class="modal-header">
                <p class="modal-title" id="modal-label">削除しますか？</p>
              </div>
              <!-- 6.モーダルのフッタ -->
              <div class="modal-footer">
                <form method="POST" action="{{route('destroy',['id' => $question->id])}}">
                  @csrf
                  @method('delete')
                  <button class="btn btn-danger" data-id="{{ $question->id }}" type="submit">削除する</button>
                </form>
                <button type="button" class="btn btn-default" data-dismiss="modal">閉じる</button>
              </div>

            </div>
          </div>
        </div>
      </div>
      @endif
      @endauth

      <div class="timeline-TweetList-tweet">
        <div class="timeline-Tweet">
          <div class="timeline-Tweet-author">
            <div class="TweetAuthor">
              <a class="TweetAuthor-link" href="#channel"> </a>
              <span class="TweetAuthor-avatar">
                <div><i class="far fa-user"></i></div>
              </span>
              <form action="/test/mypage" method="post">
                @csrf
                <input type="submit" name="id" value="{{$users->find($question->id)->user->name}}">
                <span class="Icon Icon--verified"></span>
              </form>
              <!--<span class="TweetAuthor-name">{{$users->find($question->id)->user->name}}</span>-->
            </div>
          </div>
          <label>
            <a href="{{ action('QuestionController@detail', $question->id) }}">
              <div class="timeline-Tweet-text">
                <td>{{$question->title}}</td>
                <td>{{$question->content}}</td>
              </div>
            </a>
          </label>
          <div class="timeline-Tweet-metadata"><span class="timeline-Tweet-timestamp">{{$question->created_at}}</span></div>
          <ul class="timeline-Tweet-actions">
            @auth
            @if($likes->where('user_id',Auth::user()->id)->where('question_id',$question->id)->first())
            <li class="timeline-Tweet-action">
              <a class="js-like-toggle loved" href="" data-questionid="{{$question->id}}">
                <i class="fas fa-heart"></i>
              </a>
              <span class="likesCount">{{$question->question_likes_count}}</span>
            </li>
            @else
            <li class="timeline-Tweet-action">
              <a class="js-like-toggle" href="" data-questionid="{{$question->id}}">
                <i class="active far fa-heart"></i>
              </a>
              <span class="likesCount">{{$question->question_likes_count}}</span>
            </li>
            @endif
            @endauth

            @guest
            <p class="favorite-marke">
              <a class="js-like-toggle loved" href="" data-questionid="{{$question->id}}">
                <i class="fas fa-heart"></i>
              </a>
              <span class="likesCount">{{$question->question_likes_count}}</span>
            </p>
            @endguest

          </ul>
        </div>
      </div>
    </div>
    <br>
    @endforeach

    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
    <script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js"></script>
    <script src="{{ mix('js/_questionlike.js') }}"></script>
  </div>
</div>
@endsection
```

下記ajaxによる処理を記載します。
"data-questionid"と定義されている箇所と$this.data('questionid')をjavascriptでリンクさせています。
いいねを表すハートマークには、fontawsomeを使用しています。
farが黒塗りハート（♥）、fasが白塗りハート（♡）と対応しています。
今まで何となくクラスとかインデントを記述していましたが、javascriptとの連携をやってみて、きちんと定義してあげることの必要性が分かった気がします。


```javascript:_questionlike.js
$(function () {
    var like = $('.js-like-toggle');
    var likeQuestionId;
    like.on('click', function () {
        var $this = $(this);
        likeQuestionId = $this.data('questionid');
        $.ajaxSetup({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            }
        });

        $.ajax({
            headers: {
                'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content')
            },
            url: '/questionlike',  //routeの記述
            type: 'POST', //受け取り方法の記述（GETもある）
            data: {
                'question_id': likeQuestionId //コントローラーに渡すパラメーター
            },
        })

            // Ajaxリクエストが成功した場合
            .done(function (data) {
                //lovedクラスを追加
                $this.toggleClass('loved');
                $this.children('i').toggleClass('fas');
                $this.children('i').toggleClass('far');
                console.log('sucesssss');


                //.likesCountの次の要素のhtmlを「data.postLikesCount」の値に書き換える
                $this.next('.likesCount').html(data);

            })
            // Ajaxリクエストが失敗した場合
            .fail(function (data, xhr, err) {
                console.log('エラー');
                console.log(err);
                console.log(xhr);
            });

        return false;
    });
});
```

```php:QuestionController.php
//いいね機能対応箇所のみ
public function ajaxlike(Request $request)
    {
        $id = Auth::user()->id;
        $question_id = $request->question_id;
        $like = QuestionLike::where('question_id', $question_id)->where('user_id', $id)->first();
        $question = Question::findOrFail($question_id);

        if ($like) {
            //likesテーブルのレコードを削除
            $like = QuestionLike::where('question_id', $question_id)->where('user_id', $id)->delete();
        } else {
            QuestionLike::create(['user_id' => $id, 'question_id' => $question_id]);
        }

        $questionLikesCount = $question->loadCount('question_likes')->question_likes_count;
        //これがajaxのdataとして渡される
        print($questionLikesCount);
    }
```

データベースと連携させてあげればトップ画面のような、よく見るいいねボタンが実装できると思います。