wotzebra / livewire-sortablejs

A Laravel Livewire plugin that makes it easy to use Sortable.js
MIT License
292 stars 24 forks source link

How can I know if everything is loaded and ready to be used ? #39

Open joffreypersia opened 1 year ago

joffreypersia commented 1 year ago

Hi,

I just installed the package according to the instructions (from npm + added the lines in the app.js). I added the attributes to the differents elements like the doc :

<ul wire:sortable="updateTaskOrder" wire:sortable.options="{ animation: 100 }">
    @foreach ($tasks as $task)
        <li wire:sortable.item="{{ $task->id }}" wire:key="task-{{ $task->id }}">
            <h4>{{ $task->title }}</h4>
            <button wire:sortable.handle>drag</button>
        </li>
    @endforeach
</ul>

But the handle doesn't do anything when I am clicking and dragging.

Is there a way to make sure the elements are correctly loaded ? I am trying to use the inside a tbody (to drag / sort tr) Should I also import and assign to the window Sortable ? or is it included in your instructions ?

Thank you

gdebrauwer commented 1 year ago

Can you provide a code snippet so I can reproduce the bug?

joffreypersia commented 1 year ago

Can you provide a code snippet so I can reproduce the bug?

Thank you for your quick answer, it is the first time I am trying to use Sortable.js and your package.

Unfortunately, I can't give you the snippet because my app is quite complex and I am working with a team.

To clarify what I did : npm install sortablejs --save Then in my app.js (Laravel/Livewire app) I added the lines

// app.js
[...]
import '@nextapps-be/livewire-sortablejs';
[...]
Livewire.start()

Then In my Livewire table component is something like :

// table-structure.blade.php
@props([
    'headerType' => 'default', // sticky, default
    'orderable' => false,
])
<table
    {{ $attributes->merge(['class' => 'min-w-full']) }}
    x-data="{
        orderable: @entangle('orderable'),
        init() {
            $nextTick(() => {
                console.log('orderable', this.orderable);
                if (this.orderable) {
                    const elements = document.querySelectorAll('tbody[sortable]');
                    elements.forEach(element => {
                        let sortable = Sortable.create(element);
                        console.log(element);
                    });
                }
            });
        }
    }"
>
    <thead class="">
        <tr>
            {{ $head }}
        </tr>
    </thead>
    <tbody class="divide-shade-200 dark:divide-shade-600 divide-y" @if($orderable) sortable wire:sortable="updateOrder" wire:sortable.options="{ animation: 100 }" @endif>
        {{ $body }}
    </tbody>
</table>

And I passed the cell infos through the parent component table

@props([
    'orderable' => false,
])
<div>
    <div class="bg-white dark:bg-shade-700 border border-shade-200 dark:border-shade-600 rounded">
        <x-table-structure :orderable="$orderable">
            <x-slot name="head"></x-slot>
            <x-slot name="body">
                @forelse ($table['items'] as $item)
                    <tr
                        wire:loading.class="opacity-50"
                        @if($orderable)
                            wire:sortable.item="{{ $item['id'] }}"
                            wire:key="task-{{ $item['id'] }}"
                        @endif
                    >
                        @if($orderable)
                            <x-table.cell class="w-4 cursor-grab" wire:sortable.handle >
                                <x-heroicon-s-bars-2 class="w-4 h-4 text-shade-500 dark:text-shade-400"/>
                            </x-table.cell>
                        @endif
                        @foreach($table['config'] as $col)
                            <x-table.cell class="{{ $col['width'] }}">
                                @switch($col['type'])
                                    {{-- empty --}}
                                    @case('id')
                                        @break
                                    @case('img')
                                        <img src="{{ $item[$col['name']] }}" class="w-full h-12 object-contain"
                                             alt=""/>
                                        @break
                                    @case('url')
                                        <a href="{{ $item[$col['name']] }}" target="_blank">{{ $item[$col['name']] }}</a>
                                        @break
                                     @default
                                        {{ $item[$col['name']] }}
                                @endswitch
                            </x-table.cell>
                        @endforeach
                    </tr>
                @empty
                    <tr>
                        <x-table.cell colspan="{{sizeof($table['config'])}}">
                            <div class="flex justify-center items-center space-x-2">
                                <span
                                    class="font-medium py-8 text-cool-gray-400 text-xl">{{ __('mdall.No items found') }}</span>
                            </div>
                        </x-table.cell>
                    </tr>
                @endforelse
            </x-slot>
        </x-table-structure>
    </div>
</div>

--> Should I add more lines inside my app.js ? Should I import and load Sortable.js ? --> Should I add something to initialize Sortable ?

EDIT : It is working, my nextTick wasn't correct, I made the change and update the code above

CleanShot 2023-10-20 at 18 57 37@2x CleanShot 2023-10-20 at 19 02 28@2x

joffreypersia commented 1 year ago

I have an other trouble with the communication with the class...

I added this function in my class attached to my livewire component

    public function updateOrder() {
        dd('updateOrder');
    }

And as you can see above my tbody line aim this function

<tbody wire:sortable="updateOrder">

But the die and dump doesn't get triggered.

Have you an idea ?

gdebrauwer commented 1 year ago

Am I correct in saying that you are adding Sortable instances yourself using Javascript? (code snippet from your comment above)

<table
    {{ $attributes->merge(['class' => 'min-w-full']) }}
    x-data="{
        orderable: @entangle('orderable'),
        init() {
            $nextTick(() => {
                console.log('orderable', this.orderable);
                if (this.orderable) {
                    const elements = document.querySelectorAll('tbody[sortable]');
                    elements.forEach(element => {
                        let sortable = Sortable.create(element);
                        console.log(element);
                    });
                }
            });
        }
    }"
>

Because then it is normal that the Livewire method is not triggered, because you have to configure a lot of stuff when creating the Sortable instance in order to get that working