'Livewire Saving checkbox values as they are checked or unchecked
I have been trying to save checkbox values as they are checked by the user. No save button for this part is needed.
This is a many-to-many relationship and therefore, it’s the relation table that gets updated with the new values.
The array returned by Livewire to updatedSelected() is the same as initial values from the database and that is where I am stuck.
The problem is when values exist in the DB, load the page, uncheck one or more and the array returned to updatedSelected() is the same as it was initially loaded on page load.
On checking a checkbox the values are updated properly as I get the full array of values as expected.
When unchecking, what I am expecting is only the values that are left checked to properly sync the model.
If you have any clues on this, your help would be appreciated!
pefumes.php
public $selected = [];
protected $rules = [
"selected.*" => "required"
];
public function updatedSelected( $values )
{
$this->validate();
if( $this->plant->id != null )
{
$this->plant->perfumes()->sync(
array_map( "intval", $values )
);
}
}
perfumes.blade.php
<div class="auto-grid-placement auto-grid-item">
@foreach( $perfumes as $perfume )
@php
$slug = slugafy( $perfume->name );
@endphp
<x-form.label for="{{ $slug }}-{{ $perfume->id }}" class="{{ $disabled }} checkbox-item px-2 py-2 inline-block">
<input wire:model="selected" type="checkbox" id="{{ $slug }}-{{ $perfume->id }}" class="" value="{{ $perfume->id }}" {{ $disabled }}> {{ $perfume->name }} - {{ $perfume->id }}
</x-form.label>
@endforeach
</div>
To further express the issue.
Solution 1:[1]
try this
public $selected = [];
protected function rules()
{
return [
...
'selected' => 'required|array',
];
}
public function edit()
{
if ($this->validate()) {
$data = [
'name' => $this->name,
...
];
$plant = Plant::where('id', $this->plant->id)->update($data);
if (!empty($this->selected)) {
$selectedId = Perfume::whereIn('id', $this->selected)->pluck('id');
Plant::findOrFail($this->plant->id)->perfumes()->sync($selectedId);
}
}
}
Solution 2:[2]
I was able to get through this by changing the wire:model="selected" to wire:click=”savePerfumes( $perfume->id)” by calling a method to filter and save the input values. This is the example that got me on the right track: https://www.youtube.com/watch?v=gNuWLHiRn-o
I must then conclude that the approach of calling the wire:model=”selectedPerfume”, the set array, on every checkbox is probably better, if not made for, single-use checkboxes and these are not checked from values from the DB on load, like most examples you see.
If one needs to check and uncheck checkboxes, this is my approach:
The view
<div class="auto-grid-placement auto-grid-item">
@foreach( $perfumes as $perfume )
@php
$slug = slugafy( $perfume->name );
$checked = ( in_array( $perfume->id, $selectedPerfumes->toArray() )? "checked='checked'" : "")
@endphp
<x-form.label for="{{ $slug }}-{{ $perfume->id }}" class="{{ $disabled }} checkbox-item px-2 py-2 inline-block">
<input wire:click="savePerfumes( {{ $perfume->id }} )" type="checkbox" id="{{ $slug }}-{{ $perfume->id }}" name="selectedPerfumes[]" {{ $checked }} class="" value="{{ $perfume->id }}" {{ $disabled }}> {{ $perfume->name }} - {{ $perfume->id }}
</x-form.label>
@endforeach
@error( "selectedPerfumes" )
<span class="error">{{ $message }}</span>
<!-- /.error -->
@enderror
</div>
The function to save
// Rules
protected $rules = [
"selectedPerfumes" => "array",
"selectedPerfumes.*" => "required|integer"
];
public function savePerfumes( $perfume_id )
{
$this->validate();
if( $this->selectedPerfumes->contains( $perfume_id ))
{
$this->selectedPerfumes = $this->selectedPerfumes->reject( function( $value ) use ($perfume_id) {
return $value == $perfume_id;
});
}else{
$this->selectedPerfumes->push( $perfume_id );
}
if( $this->plant->id != null )
{
$this->plant->perfumes()->sync(
$this->selectedPerfumes
);
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Abdulmajeed |
| Solution 2 | Marc DG |
