### Install Livewire Sortable via NPM
Source: https://github.com/livewire/sortable/blob/master/README.md
Install the package using npm and import it into your bundle. This method is suitable for projects managed with npm.
```bash
npm install livewire-sortable --save-dev
```
```javascript
import 'livewire-sortable'
// Or.
require('livewire-sortable')
```
--------------------------------
### Minimal Sortable List Example
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
This example demonstrates a basic sortable list in a Blade template and the corresponding Livewire component method to handle order updates.
```html
@foreach ($tasks as $task)
{{ $task->title }}
@endforeach
```
```php
public function updateTaskOrder($items) {
foreach ($items as $item) {
Task::where('id', $item['value'])
->update(['order' => $item['order']]);
}
}
```
--------------------------------
### Before Handle-Only Dragging
Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md
This example shows the default behavior where dragging can be initiated from anywhere within the list item.
```blade
```
--------------------------------
### Simple List Sorting with Livewire Sortable
Source: https://github.com/livewire/sortable/blob/master/README.md
Use `wire:sortable`, `wire:sortable.item`, and `wire:sortable.handle` for basic sortable lists like a todo list. This example shows how to structure the markup for a sortable task list.
```html
@foreach ($tasks as $task)
{{ $task->title }}
@endforeach
```
--------------------------------
### Install Livewire Sortable via CDN
Source: https://github.com/livewire/sortable/blob/master/README.md
Include this script tag in your HTML to use Livewire Sortable via a CDN. Ensure you are using Livewire v3.
```html
```
--------------------------------
### JavaScript Example of Data Conversion
Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md
Illustrates how numeric and string values are represented in JavaScript before being sent to PHP. Note that 'value' remains a string.
```javascript
{ order: 1, value: '42' }
```
--------------------------------
### Handle Drag Start Event in JavaScript
Source: https://github.com/livewire/sortable/blob/master/_autodocs/INDEX.md
Use this JavaScript snippet to execute custom logic when a drag operation begins. Attach event listeners to the sortable instance.
```javascript
sortable.on('drag:start', (event) => {
// Handle drag start
});
```
--------------------------------
### Example Sortable Item List Payload
Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md
An example of the JavaScript object passed to a Livewire method when a simple sortable list is reordered.
```javascript
[
{ order: 1, value: "task-42" },
{ order: 2, value: "task-18" },
{ order: 3, value: "task-99" }
]
```
--------------------------------
### Livewire Component Method for Updating Order
Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md
Example of a Livewire component method that receives the reordered item data and updates the database accordingly.
```php
update(['order' => $item['order']]);
}
}
public function render() {
return view('livewire.task-list', [
'tasks' => Task::orderBy('order')->get()
]);
}
}
?>
```
--------------------------------
### HTML Structure for Sortable Groups and Items
Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md
Example HTML demonstrating how to structure nested draggable groups and items using Livewire's `wire:sortable` and `wire:sortable-group` directives. It includes methods for reordering groups and tasks, and for adding new tasks and groups.
```html
@foreach ($groups as $group)
{{ $group->label }}
@foreach ($group->tasks()->orderBy('order')->get() as $task)
{{ $task->title }}
@endforeach
@endforeach
```
--------------------------------
### Checking Livewire Sortable Plugin Activation
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Use this JavaScript code to verify if the Livewire and Sortable plugins are loaded, if the directive is registered, and if a Sortable instance is active on a specific container. It also includes an example of manually triggering a 'drag:start' event.
```javascript
// Check if plugin loaded
console.log('Livewire:', window.Livewire);
console.log('Sortable:', window.Sortable);
// Check if directive is registered
const container = document.querySelector('[wire\:sortable="updateTaskOrder"]');
console.log('Container:', container);
console.log('Sortable instance:', container?.livewire_sortable);
// Manually inspect event handlers
if (container?.livewire_sortable) {
console.log('Sortable is active on this container');
// Try to trigger an event
container.livewire_sortable.on('drag:start', () => {
console.log('Drag started!');
});
}
```
--------------------------------
### Efficiently Update Task Order in Bulk
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
This method provides a more efficient way to update task orders by preparing updates and then executing them. It also shows an example of a raw query for upserting, which should be used with caution.
```php
public function updateTaskOrder($items) {
$updates = [];
foreach ($items as $item) {
$updates[$item['value']] = $item['order'];
}
foreach ($updates as $id => $order) {
Task::where('id', $id)->update(['order' => $order]);
}
// Or with raw query (use with caution):
// DB::table('tasks')->upsert(
// array_map(fn($id, $order) => ['id' => $id, 'order' => $order],
// array_keys($updates),
// $updates),
// 'id',
// ['order']
// );
}
```
--------------------------------
### Nested Sortable Group List Example Data
Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md
An example of the data structure for a nested sortable list, representing groups and their items.
```javascript
[
{
order: 1,
value: "backlog",
items: [
{ order: 1, value: "task-1" },
{ order: 2, value: "task-3" }
]
},
{
order: 2,
value: "in-progress",
items: [
{ order: 1, value: "task-2" },
{ order: 2, value: "task-5" }
]
},
{
order: 3,
value: "done",
items: [
{ order: 1, value: "task-4" }
]
}
]
```
--------------------------------
### Livewire Component Method Definition
Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md
Example of a public method in a Livewire component that can be called from JavaScript to handle reordering. It accepts the serialized order data as an argument.
```php
public function updateTaskOrder($items) {
// Handle reordering
}
```
--------------------------------
### Race Condition Example in Livewire Sortable
Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md
Rapid succession of drag operations can lead to multiple wire calls being enqueued before the first completes, potentially causing conflicts. Mitigation strategies like optimistic locking or version columns in the database are recommended.
```text
1. First drag: setTimeout(..., 1) enqueues the wire call
2. Second drag: Another wire call enqueued (before first completes)
3. Both calls are sent (order depends on network timing)
```
--------------------------------
### Nested Sortable Groups with Livewire Sortable
Source: https://github.com/livewire/sortable/blob/master/README.md
Implement nested sortable elements, similar to Trello boards, using `wire:sortable-group` attributes. This example demonstrates a structure for draggable groups containing draggable tasks.
```html
@foreach ($groups as $group)
{{ $group->label }}
@foreach ($group->tasks()->orderBy('order')->get() as $task)
{{ $task->title }}
@endforeach
@endforeach
```
--------------------------------
### After Handle-Only Dragging
Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md
This example restricts dragging to only the `
` element, allowing other elements like links to be clicked normally.
```blade
```
--------------------------------
### Initialize Sortable Instance for Groups
Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md
Initializes a new Sortable instance for the `wire:sortable-group` directive. It starts with an empty array of containers, as they are added dynamically via the `item-group` modifier.
```javascript
const sortable = el.livewire_sortable = new Sortable([], options);
```
--------------------------------
### NPM Scripts for Build and Test (JSON)
Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md
Defines the npm scripts for building, watching, and testing the Livewire Sortable project. Includes commands for one-time builds, watch mode, running tests, and debugging tests.
```json
{
"build": "npx rollup -c",
"watch": "npx rollup -c -w",
"test": "npx jest",
"test:debug": "node --inspect node_modules/.bin/jest --runInBand"
}
```
--------------------------------
### Load Livewire and Sortable Scripts
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Ensure Livewire and Livewire Sortable scripts are loaded in the correct order. Livewire should be loaded before Livewire Sortable.
```html
```
--------------------------------
### Check Sortable.js Loading
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Verify if the bundled Sortable.js is loaded. If undefined, ensure `livewire-sortable.js` or the CDN script is loaded in the correct order after Livewire.
```javascript
console.log(window.Sortable);
```
--------------------------------
### Initialize Sortable Container
Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md
Use 'wire:sortable' on the parent container to initialize Sortable. It expects the name of the Livewire method to invoke when sorting completes.
```html
```
--------------------------------
### Livewire Kanban Board Component (PHP)
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
This Livewire component manages the Kanban board's state and logic. It handles fetching groups and tasks, updating their order via `updateGroupOrder` and `updateTaskOrder` methods, creating new tasks, and deleting existing ones. The `render` method fetches and orders the data, while specific methods respond to user interactions like reordering and task creation.
```php
TaskGroup::with('tasks')->orderBy('order')->get(),
]);
}
public function updateGroupOrder($groups) {
// $groups = [
// [
// 'order' => 1,
// 'value' => 'backlog',
// 'items' => [...]
// ],
// ...
// ]
foreach ($groups as $groupData) {
TaskGroup::where('id', $groupData['value'])
->update(['order' => $groupData['order']]);
}
}
public function updateTaskOrder($groups) {
// Called whenever items are reordered (group or item drag)
foreach ($groups as $groupData) {
foreach ($groupData['items'] as $itemData) {
Task::where('id', $itemData['value'])
->update([
'task_group_id' => $groupData['value'],
'order' => $itemData['order'],
]);
}
}
}
public function createTask($groupId) {
if (empty($this->newTaskTitle)) {
return;
}
Task::create([
'task_group_id' => $groupId,
'title' => $this->newTaskTitle,
'order' => Task::where('task_group_id', $groupId)->max('order') + 1,
]);
$this->newTaskTitle = '';
}
public function deleteTask($id) {
Task::destroy($id);
}
public function editTask($id) {
$this->editingTaskId = $id;
// Show modal, etc.
}
}
?>
```
--------------------------------
### Ignore Elements During Drag
Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md
Apply 'wire:sortable.ignore' to elements or their ancestors to prevent dragging from starting when interacting with them. This is useful for buttons or forms within sortable items.
```html
{{ $task->title }}
```
--------------------------------
### Rollup Build Configuration (JavaScript)
Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md
Configuration file for Rollup, a module bundler used to build the Livewire Sortable library. It specifies entry points, output formats (UMD), and includes plugins for commonjs, resolution, filesize reporting, minification with Terser, and Babel transpilation.
```javascript
export default {
input: 'src/index.js',
output: {
name: 'Sortable',
file: 'dist/livewire-sortable.js',
format: 'umd',
sourcemap: true,
},
plugins: [
commonjs(),
resolve(),
filesize(),
terser({ compress: { drop_debugger: false } }),
babel({ exclude: 'node_modules/**' })
]
}
```
--------------------------------
### Check Livewire Loading
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Verify if Livewire is loaded in the browser. If undefined, ensure `@livewireScripts` is included in your layout before the sortable script.
```javascript
console.log(window.Livewire);
```
--------------------------------
### Cancel Drag on Ignore Attribute or Parent
Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md
Listens for the 'drag:start' event from Shopify's Sortable. It cancels the drag operation if the target element or any of its ancestors have the 'wire:sortable.ignore' attribute.
```javascript
sortable.on('drag:start', (event) => {
const target = event.originalEvent.target;
if (target.hasAttribute('wire:sortable.ignore') || findNearestParentByAttribute(target)) {
event.cancel()
}
});
```
--------------------------------
### Initialize Shopify Sortable Instance
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
Instantiate a new Sortable object with containers and options. This is an internal method used by the plugin.
```javascript
const sortable = new Sortable(containers, options)
```
--------------------------------
### Create Shopify Sortable Instance
Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md
Instantiates the Shopify Sortable class with the provided DOM element and options. The Sortable instance is managed internally by the Shopify library.
```javascript
const sortable = new Sortable(el, options);
```
--------------------------------
### Prevent Accidental Drag with Livewire Sortable
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
Prevent accidental drag operations on sortable items by using `wire:sortable.ignore` on elements that should not initiate a drag, such as form inputs or submit buttons. This example shows how to ignore a form submission.
```html
{{ $title }}
```
--------------------------------
### Implement Database Update Logic
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Ensure your Livewire method iterates through the received items and updates the database accordingly. Log received items to verify.
```php
public function updateTaskOrder($items) {
// Are you actually updating?
foreach ($items as $item) {
Task::where('id', $item['value'])
->update(['order' => $item['order']]);
}
}
Add logging:
public function updateTaskOrder($items) {
\Log::info('Received items:', $items);
// Will show in storage/logs/laravel.log
}
```
--------------------------------
### Ignore Dragging with wire:sortable.ignore
Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md
Use the `wire:sortable.ignore` modifier on an element to prevent drag operations from starting on it, even if it's part of a sortable list or group. This is useful for elements like delete buttons within sortable items.
```html
⋮
{{ $task->title }}
```
--------------------------------
### Check Database Column and Tinker
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Verify that the 'order' column exists in your database table and is writable. Use `php artisan tinker` to test direct updates.
```bash
php artisan tinker
>>> Task::first()->update(['order' => 999])
>>> Task::first()->order
```
--------------------------------
### Livewire Sortable Event Flow
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
Illustrates the sequence of events triggered when a user interacts with a sortable list, from the initial drag to the final database update.
```text
User drags item
↓
drag:start event (checked for ignore)
↓
Item moves visually
↓
User releases
↓
sortable:stop event
↓
setTimeout(..., 1) defers update
↓
component.$wire.call(methodName, items)
↓
Livewire sends HTTP request
↓
PHP method executes
↓
Database updated
```
--------------------------------
### Kanban Board HTML Template (Blade)
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
This Blade template defines the structure of the Kanban board, including groups and tasks. It utilizes Livewire's `wire:sortable` and `wire:sortable-group` directives to enable drag-and-drop functionality for both group and item reordering. Each task and group has a unique key for Livewire's diffing.
```blade
@foreach ($groups as $group)
{{ $group->label }}
({{ $group->tasks->count() }})
@foreach ($group->tasks()->orderBy('order')->get() as $task)
```
--------------------------------
### Livewire Component Methods for Sorting
Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md
PHP code for a Livewire component demonstrating how to handle the reordering of groups and tasks. It includes methods to update the order in the database based on the data received from the front-end sorting events.
```php
update(['order' => $groupData['order']]);
}
}
public function updateTaskOrder($groups) {
foreach ($groups as $groupData) {
foreach ($groupData['items'] as $itemData) {
Task::where('id', $itemData['value'])
->update(['order' => $itemData['order']]);
}
}
}
public function render() {
return view('livewire.board-view', [
'groups' => TaskGroup::with('tasks')->orderBy('order')->get()
]);
}
}
?>
```
--------------------------------
### Paginate Tasks in Livewire Component
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Implement pagination to reduce the number of DOM elements when dealing with large lists. This limits the fetched tasks to a manageable number.
```php
public function render() {
return view('livewire.task-list', [
'tasks' => Task::orderBy('order')
->limit(50) // Paginate
->get(),
]);
}
```
--------------------------------
### Livewire Component Methods for Order Updates
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
Implement `updateGroupOrder` to reorder top-level groups and `updateTaskOrder` to reorder tasks within their groups. Both methods receive structured data representing the new order.
```php
public function updateGroupOrder($groups) {
foreach ($groups as $groupData) {
TaskGroup::where('id', $groupData['value'])
->update(['order' => $groupData['order']]);
}
}
```
```php
public function updateTaskOrder($groups) {
foreach ($groups as $groupData) {
foreach ($groupData['items'] as $itemData) {
Task::where('id', $itemData['value'])
->update([
'task_group_id' => $groupData['value'],
'order' => $itemData['order'],
]);
}
}
}
```
--------------------------------
### Handle-Only Drag with Livewire Sortable
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
Implement handle-only drag-and-drop by specifying a handle element using `wire:sortable.handle`. This allows only the designated handle to initiate the drag, while other elements like buttons can be ignored using `wire:sortable.ignore`.
```html
⋮⋮{{ $title }}
```
--------------------------------
### HTML Template for Sortable Task List
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
Defines the structure for a sortable task list using Livewire directives. Ensure each item has a unique `wire:key` and the list has a `wire:sortable` attribute.
```blade
@foreach ($tasks as $task)
⋮⋮{{ $task->title }}
@endforeach
```
--------------------------------
### Verify Task Order in Tinker
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Use this Artisan Tinker command to check if the 'order' column in your database is being updated correctly after drag-and-drop operations.
```bash
php artisan tinker
>>> Task::orderBy('order')->get()->pluck('id', 'order')
```
--------------------------------
### Handle Detection Logic
Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md
This JavaScript code demonstrates how the plugin checks for the presence of a handle element to configure drag behavior.
```javascript
if (el.querySelector('[wire\:sortable\.handle]')) {
options.handle = '[wire\:sortable\.handle]'
}
```
--------------------------------
### Check Method Signature
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
The Livewire sortable method must accept a single parameter, which is an array of the sorted items.
```php
// Correct
public function updateTaskOrder($items) {
// Wrong (no parameters)
public function updateTaskOrder() {
```
--------------------------------
### CSS for Sortable Task List Styling
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
Provides styling for the sortable task list, including item appearance, drag handles, and delete buttons. Includes styles for the dragging state to provide visual feedback.
```css
.task-item {
padding: 12px;
border: 1px solid #ddd;
border-radius: 4px;
margin-bottom: 8px;
background: white;
display: flex;
justify-content: space-between;
align-items: center;
}
.task-item.draggable-source--is-dragging {
opacity: 0.5;
background: #f9f9f9;
}
.task-handle {
cursor: move;
flex: 1;
display: flex;
align-items: center;
gap: 8px;
}
.task-handle:hover {
color: #007bff;
}
.drag-icon {
color: #999;
font-size: 12px;
}
.btn-delete {
background: none;
border: none;
color: #dc3545;
cursor: pointer;
padding: 4px 8px;
font-size: 16px;
}
.btn-delete:hover {
color: #c82333;
}
body.draggable--is-dragging {
cursor: grabbing;
}
```
--------------------------------
### Optional Chaining for Livewire Access
Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md
Use optional chaining to safely access Livewire directives, preventing errors if Livewire is not loaded on the page.
```javascript
window.Livewire?.directive(...)
```
--------------------------------
### Check Method Visibility
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
The sortable method must be public. Private or protected methods will not be invoked by Livewire.
```php
// Correct
public function updateTaskOrder($items) {
// Wrong (private or protected)
private function updateTaskOrder($items) {
```
--------------------------------
### PHP Livewire Receiver for Item Reordering
Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md
PHP method to update the order of items within groups when they are reordered. Assumes a `Task` model.
```php
public function updateTaskOrder($groups) {
// Called when items are reordered (may also receive full group structure)
foreach ($groups as $groupData) {
foreach ($groupData['items'] as $itemData) {
Task::where('id', $itemData['value'])
->update(['order' => $itemData['order']]);
}
}
}
```
--------------------------------
### Verify Livewire Component Initialization
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Ensure the Livewire component is correctly initialized in your Blade view using the @livewire directive.
```blade
@livewire('task-list')
Not:
@include('livewire.task-list')
```
--------------------------------
### Correct Livewire Sortable Handle Attribute
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Demonstrates the correct HTML attribute usage for specifying a sortable handle. The `wire:sortable.handle` attribute should be placed directly on the element.
```html
Title
Title
```
--------------------------------
### Simple Sortable List
Source: https://github.com/livewire/sortable/blob/master/_autodocs/README.md
Use this snippet to create a basic sortable list. The `wire:sortable` directive handles the sorting logic, and `wire:sortable.item` identifies individual sortable elements.
```html
@foreach ($tasks as $task)
{{ $task->title }}
@endforeach
```
--------------------------------
### PHP Livewire Receiver for Group Reordering
Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md
PHP method to update the order of groups when they are reordered in the UI. Assumes a `TaskGroup` model.
```php
public function updateGroupOrder($groups) {
// Called when groups are reordered
foreach ($groups as $groupData) {
TaskGroup::where('id', $groupData['value'])
->update(['order' => $groupData['order']]);
}
}
```
--------------------------------
### Livewire Method for Group Reordering
Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md
This is the expected signature for the Livewire method that handles reordering within nested sortable groups. It receives a structured array of groups, their order, and their nested items.
```php
public function updateTaskOrder($groups) {
// $groups = [
// [
// 'order' => 1,
// 'value' => 'group-1',
// 'items' => [
// ['order' => 1, 'value' => 'task-1'],
// ['order' => 2, 'value' => 'task-2']
// ]
// ],
// ...
// ]
}
```
--------------------------------
### Bulk Update Order with Livewire Sortable
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
Handle bulk updates for sortable items by receiving an array of items with their values and orders. This PHP snippet demonstrates iterating through the received items and updating their order in the database.
```php
public function updateTaskOrder($items) {
foreach ($items as $item) {
Task::where('id', (int)$item['value'])
->update(['order' => $item['order']]);
}
}
```
--------------------------------
### Optimize Task Order Updates
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Improve the performance of updating task orders by consolidating multiple database queries into a more efficient batch update. Avoid slow individual updates within a loop.
```php
// Slow
foreach ($items as $item) {
Task::where('id', $item['value'])->update(['order' => $item['order']]);
}
// Faster (single query)
$updates = [];
foreach ($items as $item) {
$updates[$item['value']] = ['order' => $item['order']];
}
foreach ($updates as $id => $data) {
Task::where('id', $id)->update($data);
}
```
--------------------------------
### Trace Wire Method Calls in PHP
Source: https://github.com/livewire/sortable/blob/master/_autodocs/event-handling.md
Add logging within a Livewire method to trace wire method calls, such as 'updateTaskOrder'. Check Laravel's log file for the logged information after sorting.
```php
public function updateTaskOrder($items) {
foreach ($items as $item) {
Task::where('id', $item['value'])->update(['order' => $item['order']]);
}
}
```
--------------------------------
### Initialize Nested Sortable Groups
Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md
Use `wire:sortable` and `wire:sortable-group` on the same root element to initialize nested sortable functionality. The `wire:sortable-group` method will be invoked for item reordering within groups.
```html
```
--------------------------------
### JavaScript Extraction Logic
Source: https://github.com/livewire/sortable/blob/master/_autodocs/data-structures.md
Demonstrates how the `order` and `value` properties are extracted from DOM elements to form the sortable item list.
```javascript
el.querySelectorAll('[wire\:sortable\.item]').forEach((el, index) => {
items.push({ order: index + 1, value: el.getAttribute('wire:sortable.item')})
})
```
--------------------------------
### Kanban Board CSS
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
Provides comprehensive CSS for styling a Kanban board, including layout, columns, task cards, and interactive elements. This CSS enables a visually appealing and functional drag-and-drop interface.
```css
.kanban-board {
display: flex;
gap: 16px;
padding: 16px;
background: #f5f5f5;
overflow-x: auto;
min-height: 100vh;
}
.kanban-column {
flex: 0 0 320px;
background: white;
border-radius: 8px;
overflow: hidden;
display: flex;
flex-direction: column;
box-shadow: 0 2px 4px rgba(0,0,0,0.1);
}
.kanban-column.draggable-source--is-dragging {
opacity: 0.6;
}
.column-header {
padding: 16px;
border-bottom: 2px solid #e0e0e0;
cursor: move;
user-select: none;
}
.column-header h3 {
margin: 0;
font-size: 16px;
font-weight: 600;
display: flex;
align-items: center;
gap: 8px;
}
.task-count {
color: #999;
font-size: 14px;
}
.task-list {
list-style: none;
padding: 12px;
flex: 1;
overflow-y: auto;
min-height: 200px;
}
.task-card {
background: #f9f9f9;
border: 1px solid #e0e0e0;
border-radius: 4px;
padding: 12px;
margin-bottom: 12px;
cursor: move;
display: flex;
justify-content: space-between;
align-items: flex-start;
gap: 8px;
transition: all 0.2s;
}
.task-card:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
border-color: #007bff;
}
.task-card.draggable--over {
background: #e3f2fd;
border-color: #2196f3;
}
.task-content {
flex: 1;
min-width: 0;
}
.task-content h4 {
margin: 0 0 4px 0;
font-size: 14px;
font-weight: 600;
word-break: break-word;
}
.task-content p {
margin: 0 0 8px 0;
font-size: 12px;
color: #666;
line-height: 1.4;
}
.task-meta {
display: flex;
gap: 4px;
align-items: center;
}
.badge {
display: inline-block;
padding: 2px 6px;
border-radius: 3px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
}
.badge {
background: #fff3cd;
color: #856404;
}
.badge:is(.high) {
background: #f8d7da;
color: #721c24;
}
.badge:is(.low) {
background: #d1ecf1;
color: #0c5460;
}
.avatar {
width: 20px;
height: 20px;
border-radius: 50%;
}
.task-actions {
display: flex;
gap: 4px;
opacity: 0;
transition: opacity 0.2s;
}
.task-card:hover .task-actions {
opacity: 1;
}
.btn-icon {
background: none;
border: none;
padding: 4px;
cursor: pointer;
color: #999;
font-size: 14px;
}
.btn-icon:hover {
color: #007bff;
}
.add-task-form {
padding: 12px;
border-top: 1px solid #e0e0e0;
display: flex;
gap: 8px;
}
.input-task {
flex: 1;
border: 1px solid #ddd;
border-radius: 4px;
padding: 8px;
font-size: 14px;
}
.input-task:focus {
outline: none;
border-color: #007bff;
box-shadow: 0 0 0 2px rgba(0, 123, 255, 0.25);
}
.btn-add {
background: #007bff;
color: white;
border: none;
border-radius: 4px;
padding: 8px 12px;
cursor: pointer;
font-weight: 600;
}
.btn-add:hover {
background: #0056b3;
}
body.draggable--is-dragging {
cursor: grabbing;
user-select: none;
}
```
--------------------------------
### Import Sortable Class
Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md
Import the Sortable class from '@shopify/draggable/lib/sortable'. This class is essential for managing sortable lists and groups.
```javascript
import Sortable from '@shopify/draggable/lib/sortable'
```
--------------------------------
### Handle Multi-User Concurrency with Locking
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
When multiple users might edit the same board, use lockForUpdate to prevent race conditions during task order updates. This locks the rows being updated.
```php
public function updateTaskOrder($items) {
foreach ($items as $item) {
$task = Task::lockForUpdate()->find($item['value']);
if ($task) {
$task->update(['order' => $item['order']]);
}
}
}
```
--------------------------------
### Listen to Shopify Sortable Events
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
Attach an event handler to a Sortable instance for a specific event type. This is an internal method.
```javascript
sortable.on(eventType, handler)
```
--------------------------------
### Correct Livewire Sortable Directive
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Ensure the `wire:sortable` directive includes a method name. The directive without a method name is incorrect.
```html
```
```html
```
--------------------------------
### Livewire Component for Task List Management
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
Manages the task list data and handles order updates and task removal. The `updateTaskOrder` method processes the reordered items, and `removeTask` deletes a specific task.
```php
Task::orderBy('order')->get(),
]);
}
public function updateTaskOrder($items) {
// $items = [
// ['order' => 1, 'value' => '42'],
// ['order' => 2, 'value' => '18'],
// ['order' => 3, 'value' => '99'],
// ]
foreach ($items as $item) {
Task::where('id', $item['value'])
->update(['order' => $item['order']]);
}
}
public function removeTask($id) {
Task::destroy($id);
}
}
?>
```
--------------------------------
### Define Group Drag Handle with `wire:sortable.handle`
Source: https://github.com/livewire/sortable/blob/master/_autodocs/directive-attributes.md
Optionally, use `wire:sortable.handle` on a specific element within the group container to designate it as the drag handle for reordering groups. If omitted, any part of the group container can trigger the drag.
```html
{{ $group->name }}
```
--------------------------------
### Check Laravel Query Logs
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Enable Laravel's query logging to inspect if UPDATE queries are being executed when sorting occurs.
```php
DB::enableQueryLog();
// ... run sorting ...
dd(DB::getQueryLog());
```
--------------------------------
### Create a Sortable List in Blade
Source: https://github.com/livewire/sortable/blob/master/_autodocs/INDEX.md
Use this Blade template to render a sortable list. The `wire:sortable` directive enables drag-and-drop functionality, and `wire:sortable.item` identifies each sortable element.
```blade
@foreach ($tasks as $task)
{{ $task->title }}
@endforeach
```
--------------------------------
### Check HTML and PHP Method Name Spelling
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
Ensure the method name in your HTML attribute exactly matches the PHP method name. This is case-sensitive.
```html
```
```php
public function updateTaskOrder($items) {
```
--------------------------------
### Deferred Execution with setTimeout
Source: https://github.com/livewire/sortable/blob/master/_autodocs/source-code-structure.md
Defer wire method calls to the next event loop tick using `setTimeout` with a delay of 1ms. This ensures DOM stability before executing Livewire actions.
```javascript
setTimeout(() => { ... }, 1)
```
--------------------------------
### Ensure `wire:key` for Dynamic Items
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
Always use `wire:key` on sortable items to ensure Livewire properly diffs the list on re-render and the Sortable instance maintains track of items. This is crucial for dynamic additions.
```blade
wire:key="item-{{ $item->id }}"
```
--------------------------------
### Initialize Sortable Group Directive
Source: https://github.com/livewire/sortable/blob/master/_autodocs/api-reference.md
This is the JavaScript initialization for the `wire:sortable-group` directive. It's used to set up the sorting behavior on the provided element.
```javascript
window.Livewire?.directive('sortable-group', ({el, directive, component}) => {
// Implementation in src/index.js lines 3–49
})
```
--------------------------------
### Force Fresh Query in Livewire Component
Source: https://github.com/livewire/sortable/blob/master/_autodocs/troubleshooting.md
When Livewire re-renders with stale data, force a fresh database query by re-fetching tasks in the `render` method. This ensures the latest order is displayed.
```php
public function updateTaskOrder($items) {
// ... update database ...
// Refresh the view data
$this->dispatch('taskOrderUpdated');
}
public function render() {
return view('livewire.task-list', [
'tasks' => Task::orderBy('order')->get(), // Fresh query
]);
}
```
--------------------------------
### Livewire Test for Simple Task Order Sorting
Source: https://github.com/livewire/sortable/blob/master/_autodocs/implementation-guide.md
This test verifies the functionality of updating task orders using Livewire. It checks if the 'taskOrderUpdated' event is dispatched and if the task orders are correctly updated in the database.
```php
use Livewire\Livewire;
test('updating task order', function () {
$tasks = Task::factory(3)->create();
Livewire::test('task-list')
->call('updateTaskOrder', [
['order' => 1, 'value' => (string) $tasks[1]->id],
['order' => 2, 'value' => (string) $tasks[0]->id],
['order' => 3, 'value' => (string) $tasks[2]->id],
])
->assertDispatched('taskOrderUpdated');
$this->assertEquals(1, $tasks[1]->fresh()->order);
$this->assertEquals(2, $tasks[0]->fresh()->order);
$this->assertEquals(3, $tasks[2]->fresh()->order);
});
```
--------------------------------
### Blade Template for Nested Sortable Groups
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
Use `wire:sortable` on the root element and `wire:sortable-group` for nested groups. Items within groups use `wire:sortable-group.item` and handles use `wire:sortable.handle` or `wire:sortable-group.handle`.
```html
@foreach ($groups as $group)
{{ $group->name }}
@foreach ($group->tasks()->orderBy('order')->get() as $task)
{{ $task->title }}
@endforeach
@endforeach
```
--------------------------------
### Data Structure for Order Updates
Source: https://github.com/livewire/sortable/blob/master/_autodocs/complete-reference.md
When sorting is complete, Livewire sends an array of items to the specified method. Each item includes its order and value.
```php
$items = [
['order' => 1, 'value' => '42'],
['order' => 2, 'value' => '18'],
]
```