DEV Community

Cover image for Like and Unlike Button with Alpine: Laravel
webfuelcode
webfuelcode

Posted on

Like and Unlike Button with Alpine: Laravel

Like and dislike buttons can be added to the Laravel project in a variety of ways. You can also use a simple form

to refresh the website, although this may not feel professional for some.

So we use JavaScript to create quick buttons similar to those found on Facebook and YouTube.

When using Laravel, we have several ways for accessing such functions. You can always get JS, but Laravel already includes a short version framework that allows you to avoid the JS setup with Laravel.

Livewire: full stack framework, that do all the JS functions in Laravel. Good for quick search, action without refreshing the page.
Alpine: Another one framework lighter than Livewire. But not always suitable for your heavy tasks. But does a lot for light or short projects.

How to get like and dislike button in Laravel with Alpine?

You have Laravel and installed breeze with below commands, will give you alpine installed.

While Laravel itself doesn't directly include AlpineJS, Laravel Breeze, a popular authentication scaffolding package, does integrate AlpineJS by default. This allows you to quickly create interactive user interfaces without the need for a full-fledged JavaScript framework like Vue or React.

 

composer create-project laravel/laravel like-app

cd like-app

composer require laravel/breeze --dev

php artisan breeze:install

php artisan migrate
npm install
npm run dev

The you will need to build the relationship between models. Like here we are going to set like by logged in users and they can remove it (no dislike button).

Another point is that you can use this to keep any kind of post. As we are here showinf you the blog like task but the same table (likes) can keep others too. Becasu the structre is:

Schema::create('likes', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('user_id'); // User who liked the item
            $table->morphs('likeable'); // Creates likeable_id and likeable_type

            // Foreign key constraint for user_id
            $table->foreign('user_id')->references('id')->on('users')->onDelete('cascade');

            // Unique constraint to ensure a user can like an item only once
            $table->unique(['user_id', 'likeable_id', 'likeable_type']);
            $table->timestamps();
        });

Image description
The column 'likeable_type' will manage all similar ids to store.

So if the blog id (1), post id (1), or offer id (1). No matter the like table will save all, so you do not need to create different tables to keep the likes.

Set the relationship between models

In blog model (blog.php) put this:

public function likes()
    {
        return $this->morphMany(Like::class, 'likeable');
    }

We will keep the record of user like and gonna check if they already liked it or not, so the action will depend on their previous act. In user model (user.php) put this:

public function likes()
    {
        return $this->hasMany(Like::class);
    }

    public function hasLiked($blog)
    {
        return $this->likes()->where('likeable_id', $blog->id)
                            ->where('likeable_type', Blog::class)
                            ->exists();
    }

One more model is like model (like.php):

public function likeable()
    {
        return $this->morphTo();
    }

The blog.blade.php will have a button to show like and count. Put this code where ever you wanna show the likes.

<div x-data="{ liked: {{ json_encode(auth()->user()->hasLiked($blog)) }}, likesCount: {{ $blog->likes->count() }} }">
                                                <button
                                                    @click="
                                                        fetch('{{ route('blogs.toggleLike', $blog->slug) }}', {
                                                            method: 'POST',
                                                            headers: {
                                                                'X-CSRF-TOKEN': '{{ csrf_token() }}',
                                                                'Content-Type': 'application/json'
                                                            },
                                                            body: JSON.stringify({})
                                                        })
                                                        .then(response => response.json())
                                                        .then(data => {
                                                            liked = data.liked;
                                                            likesCount = data.likesCount;
                                                        });
                                                    "
                                                    :class="{ 'text-blue-500': liked }"
                                                >
                                                    <span x-text="liked ? 'Unlike' : 'Like'"></span>
                                                </button>
                                                <span x-text="likesCount"></span> likes
                                            </div>

Now add function to handle like action this will check if the user has already like it or not. Here I have set the blog to open with slug not the id. For that I have used eloquent-sluggable by cviebrock. BlogController.php:

public function show(Blog $blog)
    {
        return view('show.blog', compact('blog'));
    }

public function toggleLike(Blog $blog)
    {
        $user = Auth::user();

        if ($user->hasLiked($blog)) {
            $blog->likes()->where('user_id', $user->id)->delete();
            $liked = false;
        } else {
            $blog->likes()->create(['user_id' => $user->id]);
            $liked = true;
        }

        return response()->json([
            'liked' => $liked,
            'likesCount' => $blog->likes()->count()
        ]);
    }

Now the route, web.php:

Route::post('/blog/{blog}/like', [BlogController::class, 'toggleLike'])->name('blogs.toggleLike');

Top comments (0)