Livewire 4 має вбудоване сортування перетягуванням - без сторонніх бібліотек.
<ul wire:sort="reorder">
@foreach ($this->tasks as $task)
<li wire:key="{{ $task->id }}" wire:sort:item="{{ $task->id }}">
<span wire:sort:handle>⋮⋮</span>
{{ $task->title }}
</li>
@endforeach
</ul>
Коли користувач відпускає елемент, Livewire викликає метод з ідентифікатором елемента (wire:sort:item) і новою позицією (з нуля). wire:sort:handle обмежує перетягування «ручкою».
Між кількома списками (канбан-дошка) - однакова група і ідентифікатор контейнера, що стає третім параметром:
<ul wire:sort="moveCard" wire:sort:group="cards" wire:sort:group-id="{{ $column->id }}">
Збереження порядку - ваша відповідальність, і тут легко помилитися:
public function reorder(int $taskId, int $position): void
{
$this->authorize('update', $this->project);
DB::transaction(function () use ($taskId, $position) {
$ids = $this->project->tasks()->orderBy('position')->lockForUpdate()->pluck('id');
abort_unless($ids->contains($taskId), 404); // лише задачі цього проєкту
$position = max(0, min($position, $ids->count() - 1));
$ordered = $ids->reject(fn ($id) => $id === $taskId)->values();
$ordered->splice($position, 0, [$taskId]);
foreach ($ordered as $index => $id) {
Task::whereKey($id)->update(['position' => $index]);
}
});
unset($this->tasks);
}
Що тут важливо:
- ідентифікатор і позиція - від клієнта. Без перевірки, що задача належить проєкту користувача, можна пересунути чужу задачу. Пошук через зв'язок (
$this->project->tasks()) чиfindOrFailв області видимості власника обов'язковий; - межі позиції - від'ємна чи завелика позиція не повинна ламати нумерацію;
- перенумерація в транзакції з блокуванням - два користувачі, що одночасно сортують один список, інакше отримають дублікати позицій;
- для довгих списків оновлювати лише зсунутий діапазон (
increment/decrementдля позицій між старою й новою), а не всі рядки; wire:keyна елементах обов'язковий - після відповіді сервера морфінг має зіставити елементи за ідентифікатором, а не за позицією;- для переміщення між колонками перевіряти й колонку призначення (третій параметр) - вона теж може бути чужою.
Альтернатива перенумерації - дробові чи «розріджені» позиції (крок 1000, вставка посередині між сусідами): одне оновлення замість багатьох, з періодичною перенумерацією.