Laravel

Laravel 8 Jquery drag and drop list and update to database – Livewire

Share your learning

Hey learner, Today I am gonna show you how we can use Jquery drag and drop list and update to database with Livewire. 

We will also update the drag and drop order to our database using livewire events.

Actually I have tried the livewire/sortable package first, but I didn’t find that useful for my situation. So, I turned back to jquery UI sortable. 

Anyway, let’s get started.

I assume that you have already set up your Laravel and Livewire project. So, I am not going to show that process. Just get straight to the point.

Create Livewire component

Create a new Livewire component with name DraggableList by using following command

php artisan make:livewire DraggableList

It will create the livewire component class file in the app/Http/livewire directory. One more file it will add that will be a laravel blade file in the resources/views/livewire directory. 

Well done, we are ready to perform the action. Add the jquery file in the head or footer if not added yet.

Now, our job will be divided into two parts: one is to integrate the jquery ui sortable with our html and another is to update the dragged position to our database. Wait, I think we will also need to update the order when we delete something from our list. 

Ok, we will cover that too.

Prepare livewire component

So, let’s start with the Livewire part first. As we can see we have a render method here in our component file. This method enables us to interact with our laravel blade file as a view part for this component. Now let’s add the mount method it will call before our  component is mounted or initialized. 

<?php

namespace App\Http\Livewire;

use App\Models\Lists;
use Livewire\Component;

class DraggableList extends Component
{
    public $list = [];

    protected $listeners = ["updateComponent" => "updateComponent", "ListOrderUpdated" => "ListOrderUpdated"];

    public function mount()
    {
        $this->updateComponent();
    }

    public function render()
    {
        return view('livewire.draggable-list');
    }

    public function deleteListItem( $id ) {
        $this->dispatchBrowserEvent("deletingEvent", ['id' => $id, 'type' => 'list']);
        Lists::find($id)->delete();
    }

    public function cloneListItem( $id ) {
        $list = Lists::find($id)->replicate();
        $list->position = (Lists::max("position")+1);
        $list->save();
        $this->updateComponent();
    }


    public function updateComponent()
    {
        $this->list = Lists::orderBy('position')->get();
    }

    public function ListOrderUpdated( $orderData ) {

        foreach ($orderData['lists'] as $id => $position) {
            if ($this->betweenRange($position, $orderData['min'], $orderData['max'])) {
                Lists::where('id', $id)->update([
                    'position' => $position
                ]);
            }

        }

        $this->updateComponent();
    }

    protected function betweenRange($number, $min, $max) {
        return ($number >= $min && $number <= $max);
    }


}

Through the updateComponent method we will update our list, whenever we need it to update. 

We will emit the livewire event after getting an update from jquery ui sortable. When deleting the list item we will again emit that event to update the order too.

<div>
    <div class="container d-flex align-items-center justify-content-center vh-100">


    <div class="list-group w-50 sortable">
        @foreach ($list as $item)
        <a href="#" data-list-id="{{$item['id']}}" data-list-position="{{$item['position']}}" class="list-group-item list-group-item-action list-group-item-primary d-flex align-items-center justify-content-between my-1 ui-sortable-handle">
            <i class="fas fa-arrows-alt handler"></i>
            <span>Id: {{ $item['id'] }}</span>
            <span>{{ $item['name'] }}</span>
            <span> Position: {{ $item['position'] }}</span>

            <i class="fas fa-clone" wire:click='cloneListItem({{$item["id"]}})'></i>

            <i class="fas fa-trash" wire:click='deleteListItem({{$item["id"]}})'></i>
        </a>
        @endforeach
    </div>

    </div>

    @include('inc.loader')
</div>

Update sorted order to the database

Bonus point, We will update only those records which actually affect after this sort. It will save our requests to the database. Like if we drag the 123rd item to 112th item then we will update only 112 to 123 items.

For this purpose we are already passing positions to our list item. Now when we drag the 123rd item and drop over 112th item, we have got two points. 

Let’s take the 123rd as current position and 112th as target position. After getting the min and max, we will get min = 112 and max = 123. 

So, the logic will be something like this. If the position is in between the min and max then it needs to update to the database otherwise no need to update it to the database. By this way we will ignore other items to be updated.

JQuery UI sortable to create Jquery drag and drop list

<script>
    $(document).ready(function() {

        $('.sortable').sortable({
            //axis: "y",
            //handle: ".handler",
            items: ".ui-sortable-handle",
            cursor: 'move',
            opacity: 0.6,
            update: function(event, ui) {
                updateOrderOnServer(ui.item, '.ui-sortable-handle', 'list');
            }
        })

    })

    window.addEventListener('deletingEvent', event => {
        deletingItem(event.detail.id, event.detail.type);
    });

    function deletingItem( id, type ) {
        const deletedItem = $(`[data-${type}-id='${id}']`);
        console.log('next field after delete', deletedItem.next());
        const item = deletedItem.next();

        deletedItem.remove();

        if (item.length > 0) {
            const itemClass = ".ui-sortable-handle";

            updateOrderOnServer(item, itemClass, type, 'delete');
        } else {
            //window.livewire.emit("updateComponent");
        }
    }

    function updateOrderOnServer(item, itemClass, type, action = 'order') {
        var orderData = {
            [`${type}s`]: {}
        };
        var current = $(item).data(`${type}-position`);
        var target = 0;
        var items = $(item).parent().find(itemClass);

        items.each(function(index, element) {
            console.log(index, element);
            var id = $(element).data(`${type}-id`);
            orderData[`${type}s`][id] = index+1;

            if ($(item).data(`${type}-id`) === id) {
                target = index+1;
            }
        })

        orderData['min'] = Math.min(current, target);

        if ( action==='delete' ) {
            orderData['max'] = items.length;
        } else {
            orderData['max'] = Math.max(current, target);
        }

        if ( items.length > 0 ) {
            console.log(orderData);
            window.livewire.emit("ListOrderUpdated", orderData);
        }
    }
</script>
Output screen

That’s it, this is the tutorial about Jquery drag and drop list and update to database with livewire. If you have any query let me know in the comment section below.

Satpal

Recent Posts

How to Switch PHP Versions in XAMPP Easily: Managing Multiple PHP Versions on Ubuntu

Today we are going to learn about managing multiple PHP versions on ubuntu with xampp.…

7 months ago

How to Use Coding to Improve Your Website’s SEO Ranking?

Let's understand about how to use coding to improve your website's SEO. In today’s computerized…

7 months ago

Most Important Linux Commands for Web Developers

Let's understand the most important linux commands for web developers. Linux, as an open-source and…

9 months ago

Top 75+ Laravel Interview Questions Asked by Top MNCs

Today we are going to discuss top 75+ Laravel interview questions asked by top MNCs.Laravel,…

9 months ago

Mailtrap Integration for Email Testing with Laravel 10

Today we will discuss about the Mailtrap integration with laravel 10 .Sending and receiving emails…

9 months ago

Firebase Cloud Messaging (FCM) with Ionic 6: Push Notifications

Today we are going to integrate FCM (Firebase Cloud Messaging) push notifications with ionic application.Firebase…

9 months ago