Last active
August 9, 2022 20:52
-
-
Save tanthammar/3374780f961ef53508e39cec4cdd7227 to your computer and use it in GitHub Desktop.
Livewire Sortable fix with array form
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Livewire\Traits; | |
trait Form | |
{ | |
public function reorder($reordered, $existing) | |
{ | |
if (count($reordered) > 0) { | |
foreach ($reordered as $order) { | |
$new_order[] = $existing[$order['value']]; | |
} | |
return $new_order; | |
} else { | |
return $existing; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// solves the issue to have multiple draggable instances on the same page | |
// until caleb merges https://github.com/livewire/sortable/pull/7 | |
import Sortable from '@shopify/draggable/lib/sortable'; | |
window.livewire.directive('sortable-alt', (el, directive, component) => { | |
// Only fire this handler on the "root" directive. | |
if (directive.modifiers.length > 0) return | |
let options = { draggable: '[wire\\:sortable\\.item]' } | |
if (el.querySelector('[wire\\:sortable\\.handle]')) { | |
options.handle = '[wire\\:sortable\\.handle]' | |
} | |
const sortable = new Sortable(el, options); | |
sortable.on('sortable:stop', () => { | |
setTimeout(() => { | |
let items = [] | |
el.querySelectorAll('[wire\\:sortable\\.item]').forEach((el, index) => { | |
items.push({ order: index + 1, value: el.getAttribute('wire:sortable.item') }) | |
}) | |
component.call(directive.method, items) | |
}, 1) | |
}) | |
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@push('scripts') | |
<script src="{{ mix('js/livewire-custom-sortable.js') }}"></script> | |
@endpush | |
<form> | |
<div wire:sortable-alt="updatePeopleOrder" id="update-people-order"> | |
@foreach($people as $i => $person) | |
<div wire:sortable.item="{{ $loop->index }}" wire:key="person-{{ $loop->index }}"> | |
<div> | |
<button @click.prevent.stop wire:sortable.handle> | |
your dragme button | |
</button> | |
<button wire:click.prevent="deleteItem({{ $i }})"> | |
delete item button | |
</button> | |
</div> | |
{{-- click.stop is needed to be able to select text (click+hold+drag) in form inputs, otherwise it activates the dragging behaviour --}} | |
<div @click.stop @touchstart.stop @mousedown.stop> | |
<input | |
name="title{{ $i }}" | |
type="text" | |
wire:model.lazy="people.{{ $i }}.title" | |
class="form-input @error("people.{$i}.title") error placeholder-red-300 @enderror" /> | |
<input | |
name="first_name{{ $i }}" | |
type="text" | |
wire:model.lazy="people.{{ $i }}.first_name" | |
class="form-input @error("people.{$i}.first_name") error placeholder-red-300 @enderror" /> | |
{{-- and more input tags --}} | |
</div> | |
</div> | |
@endforeach | |
</div> | |
{{-- add item --}} | |
<button wire:click.stop="addItem">Add Item</button> | |
{{-- submit button --}} | |
</form> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Http\Livewire\App\Organizers\Forms; | |
use App\Http\Livewire\Traits\Form; | |
use App\Models\Organizer; | |
use Livewire\Component; | |
class People extends Component | |
{ | |
use Form; | |
public $model; | |
public $people; | |
public function mount(Organizer $organizer) | |
{ | |
$this->fill([ | |
'model' => $organizer, | |
'people' => $organizer->people, | |
]); | |
} | |
public function updatePeopleOrder($reordered) | |
{ | |
$this->people = $this->reorder($reordered, $this->people); | |
} | |
public function deleteItem(int $i): void | |
{ | |
unset($this->people[$i]); | |
$this->people = array_values($this->people); | |
} | |
// example validation rules | |
public function getRules() | |
{ | |
return [ | |
'people.*.title' => 'required|between:2,50', | |
'people.*.first_name' => 'required|between:2,50', | |
]; | |
} | |
public function addItem(): void | |
{ | |
$this->people[] = [ | |
'title' => '', | |
'first_name' => '', | |
]; | |
} | |
public function save() | |
{ | |
$this->validate($this->getRules()); | |
$this->model->update([ | |
'people' => $this->people, | |
]); | |
$this->notify(); //see calebs sponsor screencasts | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is an example of how to create a livewire form that saves array data to a json db field.
It also solves the issue with livewire/sortable, having multiple instances on the same page.
Methods: