Laravel9でお気に入り機能的なのを練習がてら実装してみた

前回でデータを登録する感じの所まで行けました。
次はJavaScriptを使う機能の練習をしてみようと思いました。
記事画面とかで「お気に入りに登録」的なボタンを押すとお気に入り登録され、「お気に入り解除」的なボタンにテキストも変更する、そんな感じの機能を練習してみました。

とりあえず…適当に公開されてるサンプルを探してみてそれを実装していく感じで進める、そんな流れが勉強にもなって一番かなと思いました。
そして、コピペしてみてやっと気付きました…。
LaravelってjQuery読み込まれてないのね!!
くそジジイなのでjQueryなんてあって当たり前と思い込んでました…。

※注意※
ヘッダーはログイン処理を入れた時のdashboardのヘッダーを使ってます。

勿論、書いて読み込めばいいんだけど、「天下のLaravelさんだし似たようなライブラリを読み込んでるだろー」と考えて調べてみました。
名推理ですね!

ソースのヘッダーを見るとapp.jsを読み込んでました。
あと、moduleというよく分からんヤツ、/@vite/clientってのがありました。
viteってのは何か難しいヤツだよね…?それは触りたくないけど…他にjsのライブラリっぽいの見つからない…。
で、何でか経緯は忘れたけど、ネットワークタブからaxios.jsとalpine.jsってのに辿り着きました。

axios.jsについて調べて見ると通信関係っぽい感じで、jQueryのような汎用ライブラリとは違うっぽい。

alpine.jsについて調べてみると、どうやらドンピシャでVue.jsや今風のjQueryっぽい感じらしい。
これやな。

そこからalpine.jsについて更に調べていきました。
「ajax的なのはfetch()っての使えばいいのか」
「Promiseって何や?」
「何でjsonデコード(response.json())するだけでも非同期やねん?」
「コンポーネントにしたいなー。でも、データの連携どうしたら…?」
そんな感じで現代的なJavaScriptに追いついてないオッサンは四苦八苦しながら進めました。
そして一応作れたのが下記のような感じです。

    public function show( Post $post)
    {
        $isfav = Auth::user()->isFav($post->id);
        //
        return view('post.show',[
            'post' => $post,
            'isfav'=>$isfav,
        ]);
    }
<x-app-layout>
    <x-slot:title>{{ $post->title }}</x-slot>

    <x-slot:header>
        <h2 class="font-semibold text-xl text-gray-800 leading-tight">
        {{ $post->title }}
        </h2>
    </x-slot>

<script>
function fav(){
  return {
    faved : {{ $isfav ? 'true' : 'false' }},
    favText : 'ほげ',
    favUrl   : "{{ route( 'post.fav',[ 'id'=>$post->id ]) }}",
    modalOpen : false,
    modalText : '',
    doLike() {
        let faved = null;
        fetch( this.favUrl )
            .then( response => response.json() )
            .then( (json) => {
                //モーダル用
                this.modalOpen = true;
                this.modalText = this.favText + 'しました。';
                //状態変更(でないと、showがおかしくなる)
                this.faved = json.fav;
                this.favText = this.faved ? 'お気に入り登録' : 'お気に入り解除';
            });
    },
    show(){
        this.favText = this.faved ?  'お気に入り登録' :'お気に入り解除';
    },
  }
}
</script>
<section class="text-gray-600 body-font">
    <div class="container px-5 py-10 mx-auto">
        {{ $post->content }}
    </div>
    
    <div class="flex justify-center" x-data="fav()" data-recommendlist-id="{{ $recommendlist->id }}" x-init="show()">
        <span class="text-black bg-white border p-4 rounded-md shadow" x-text="favText" @click="doFav()"></span>
        <x-modal />
    </div>
</section>
</x-app-layout>
<div x-show="modalOpen" class="absolute top-0 left-0 w-screen h-screen">
    <div class="absolute w-full h-full bg-black opacity-80"></div>
    <div @click.outside="modalOpen = false" class="relative w-5/6 max-w-xl m-auto bg-gray-200 border rounded-md shadow" style="top: 20vh;" >

        <main class="">
            <p x-html="modalText" class="p-4"></p>
        </main>

        <footer class="flex justify-center" style="">
            <button @click="modalOpen = false" class="m-2 py-2 px-4 text-white bg-gray-600 hover:bg-gray-400 border rounded-md shadow">閉じる</button>
        </footer>
    </div>
</div>

大体こんな感じ。
「お気に入り登録」「お気に入り解除」をクリックすると通信して「登録しましたー」とかってメッセージが表示される感じです。
ソースは雰囲気で読んでね!
色々と試行錯誤のゴミがあるけど許してね!

基本的にラッパー要素につけたx-data=”fav()”でfavオブジェクトで色々管理する感じっすね。
正直、こうしないとクリック時の処理にデータを渡したりボタンテキストの変更などのスコープがカオスになってしまい、どういう感じで実装すればいいのか分かりませんでした…。
show.blade.phpの42行目のx-data=”fav()”ってx-dataにオブジェクトを設定する実装を見つけた時、これかー!って色々と解決しました。
x-dataを入れ子にすると、内側の要素は内側のx-dataにしかアクセス出来ないとか…ナンデ?どうしたらいいの?とかなりましたが、やってくウチに「そりゃそーかw」となりました。

あ、態々コンポーネントにしてるmodal.blade.phpは親要素のx-dataにmodalOpenとmodalTextが必須になっちゃいました…。
modalTextは引数にも出来そうだけど、modalOpenの表示・非表示フラグはどう考えても解決出来なかったんですよね。
多分、何かあるんだろうけどアル中オッサンには無理でしたw
ベタな感じの実装としてはまぁまぁな形になったかな?

こんなシンプルな機能を実装しようとしただけで、axios.jsやらalpine.jsやらfetchからのawaitやらPromiseやらTailwindcssやら色々と調べました。
ホントに進まないっすわw
でもfetchやらclasslistやらJavaScript本体に実装されると、jQueryはホントに要らない子になった感じしますね。
アニメーションやらは特化したライブラリの方が良さそうだし。

おっさん、牛歩のように進んで行きたいと思います!
「ココ、こうした方がええで!」とかあったらおねしゃす。

コメント

タイトルとURLをコピーしました