見出し画像

ミニカーコレクションSNSサービス開発④▶️開発50日目


いいね機能の非同期処理について


既に「いいね機能」の実装をしていましたが、いいねをクリックするたびにページがリロードされてしまい、せっかく下までスクロールしていたのに、再度ページ上部に戻ってしまうなどとても不便でした。
今回はそんな「いいね機能」をページリロードを伴わない、非同期処理にて改修しています。

前提としてLaravelを使用し、いいねを格納するためのデータテーブルやコントローラー、フロント側のファイルは既に完成しているものとします。ここから非同期処理の実装を行いました。

完成のイメージは、例えば以下の様なクルマの下にあるハートマークをクリックして、ハートを付けたり消したりする処理を画面のリロードをかけずに、画面上でハートマークの表示/消去ができる状態です。画面表示上ではリロードはかかりませんが、ちゃんとデータベースにいいねがついている状態or消えている状態のデータが格納されている状態です。


フロント側の記述


まず行ったのは、フロント側の修正です。
今回は<x-primary-button>タグの中に後ほど利用するための
class="ml-3 like-button liked" data-add-id="{{ $add->id }}"
の情報追加を行なっています。

というのも今回、非同期処理を行う際にjQueryとAjaxを使って処理を実装させたいので、トリガーとなるボタン<x-primary-button>タグに認識させるための追加情報が必要となるからです。

<!-- favorite 状態で条件分岐 -->

<div class="flex h-full items-center justify-center">
  @if($add->users()->where('user_id', Auth::id())->exists())
  <x-primary-button class="ml-3 like-button liked" data-add-id="{{ $add->id }}">
    <svg class="h-6 w-6 text-customYellow" fill="currentColor" viewBox="0 0 24 24" stroke="currentColor">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
    </svg>
    <span class="like-counter">{{ $add->users()->count() }}</span>
  </x-primary-button>
  @else
  <x-primary-button class="ml-3 like-button" data-add-id="{{ $add->id }}">
    <svg class="h-6 w-6 text-red-500" fill="none" viewBox="0 0 24 24" stroke="gray">
      <path stroke-linecap="round" stroke-linejoin="round" stroke-width="1" d="M4.318 6.318a4.5 4.5 0 000 6.364L12 20.364l7.682-7.682a4.5 4.5 0 00-6.364-6.364L12 7.636l-1.318-1.318a4.5 4.5 0 00-6.364 0z" />
    </svg>
    <span class="like-counter">{{ $add->users()->count() }}</span>
  </x-primary-button>
  @endif
</div>

上記で設定したクラス名に対して処理を追加していきます。
Bladeファイルの下に<script>タグ内を追記する形にしていますが、他のファイルに記述してsrcで読み込ませてもいいかもしれません。

like-buttonとして設定したクラス名に対して、onclickでイベントを発火させています。
また、Laravelを使用しているので、以下の記述も必要です。

headers: {
      'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
    },

Ajax内の記述としては、いいねのボタンがクリックされている状態の時は黄色に、クリックされていない時は何も色を適応されない様にしています。
<script>タグ全体のコードは以下です。

<!-- いいね機能の非同期処理 -->

<script>

$(document).on('click', '.like-button', function (e) {
  e.preventDefault(); // デフォルトの動作をキャンセル

  let $this = $(this);
  let likeId = $this.data('add-id');

  //いいね機能の非同期処理
  $.ajax({
    headers: {
      'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content'),
    },
    url: '{{ route('favorites.toggle') }}',
    method: 'POST',
    data: {
      add_id: likeId,
    },
  })
  .done(function (data) {
    $this.toggleClass('liked', data.liked); // liked状態のクラスを選択
    $this.find('.like-counter').html(data.likes_count); // like-counter を更新
    // いいねの色を変更
    if (data.liked) {
            $this.find('svg').attr('class', 'h-6 w-6 text-customYellow').attr('fill', 'currentColor').attr('stroke', 'currentColor');
        } else {
            $this.find('svg').attr('class', 'h-6 w-6 text-red-500').attr('fill', 'none').attr('stroke', 'gray');
        }
  })
    .fail(function () {
      console.log('Ajax Request Failed.');
    });
});


</script>

また、jQueryを使っているので、<head>タグの中にjQueryを読み込ませるソース元を記述することを忘れない様に注意が必要です。

<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>


コントローラーの記述


コントローラーの記述は、まずはログインしているユーザーを認識させ、該当のデータに対して(いいねが埋め込まれている投稿)、既にいいねしているか否かを確認。その後、JSON形式でデータを渡す内容になっています。

public function toggleLike(Request $request)
    {
        $user = Auth::user();
        $add = Add::findOrFail($request->add_id); // 投稿IDで対象データを取得

        // すでに「いいね」しているか確認
        $alreadyLiked = $add->users()->where('user_id', $user->id)->exists();
        if ($alreadyLiked) {
            // 「いいね」を解除
            $add->users()->detach($user->id);
        } else {
            // 「いいね」を追加
            $add->users()->attach($user->id);
        }
        // 最新のいいね数を取得
        $likesCount = $add->users()->count();

        // 非同期処理なのでJSONレスポンスを返す
        return response()->json([
            'liked' => !$alreadyLiked, // 現在の「いいね」状態
            'likes_count' => $likesCount,
        ]);
    }


ルーティングの設定


上記で設定したコントローラー内のtoggleLike関数に接続するルーティングにします。

Route::post('/favorites/toggle', [FavoriteController::class, 'toggleLike'])->name('favorites.toggle');


非同期処理の実装は、以上となります。
初めて使う機能だったので少し手こずってしまいましたが、なんとか非同期処理を実装できました。当初は、今の段階では非同期処理を実装せずに進めようとも思いましたが、やはり毎回いいねをする度にページがリロードされてしまうのは、かなり使いづらく感じたので、実装する運びとなりました。

ページリロードがかからずに「いいね」が付きます


今週の開発は非同期処理の実装で結構時間が掛かってしまったので、ここからペースアップして開発を進めていきたいところです💪

これからもミニカーオンラインディスプレイの開発を進めていきたいので、コメントやいいね貰えると励みになります!よろしくお願いします🙏

いいなと思ったら応援しよう!