The issue you're experiencing with the Livewire component not updating the select boxes correctly is likely due to how Livewire handles reactivity and DOM updates. When you change the group of a player, the component's state is updated, but the DOM might not be reflecting these changes correctly due to how the wire:change event is being handled.
To ensure that the select boxes are updated correctly, you can force a re-render of the component after updating the groups. One way to achieve this is by using the $refresh method provided by Livewire. This method will force the component to re-render, ensuring that the DOM is updated correctly.
Here's how you can modify your changePlayerGroup method to include a call to $refresh:
public function changePlayerGroup($playerId, $newGroupIndex)
{
// Find the player and remove from the current group
foreach ($this->groups as &$group) {
foreach ($group as $key => $player) {
if ($player->id == $playerId) {
unset($group[$key]);
break 2;
}
}
}
// Add the player to the new group
$this->groups[$newGroupIndex][] = $this->players->find($playerId);
// Force a re-render of the component
$this->emitSelf('playersGroupChanged');
}
Additionally, ensure that your component is listening for the playersGroupChanged event and calling the $refresh method:
protected $listeners = [
'playersGroupChanged' => '$refresh'
];
This will ensure that the component is re-rendered whenever the playersGroupChanged event is emitted, which should resolve the issue with the select boxes not updating correctly.
Here's the updated component code:
namespace App\Livewire;
use App\Models\League;
use Livewire\Component;
class LeaguePlayerGroups extends Component
{
public $isOpen = false;
public $league;
public $players;
public $groups = [];
protected $listeners = [
'playersGroupChanged' => '$refresh'
];
public function open()
{
$this->isOpen = true;
}
public function close()
{
$this->isOpen = false;
}
public function mount(League $league)
{
$this->league = $league;
$this->players = $league->players;
$this->setGroups();
}
public function render()
{
return view('livewire.league-player-groups');
}
private function setGroups()
{
$totalGroups = $this->calculateGroups();
$this->groups = $this->assignPlayersToGroups($totalGroups);
}
public function calculateGroups()
{
$totalPlayers = $this->players->count();
$initialGroups = intdiv($totalPlayers, 4);
$remainder = $totalPlayers % 4;
if ($remainder == 1 || $remainder == 2) {
$totalGroups = $initialGroups + 1;
} else {
$totalGroups = $initialGroups;
}
return $totalGroups;
}
private function assignPlayersToGroups($totalGroups)
{
$groups = array_fill(0, $totalGroups, []);
$playerIndex = 0;
foreach ($this->players as $player) {
$groups[$playerIndex % $totalGroups][] = $player;
$playerIndex++;
}
// Redistribute players if any group has just 1 or 2 players
foreach ($groups as $index => $group) {
if (count($group) == 1 || count($group) == 2) {
$groups[$index] = array_merge($groups[$index], array_pop($groups));
}
}
return $groups;
}
public function changePlayerGroup($playerId, $newGroupIndex)
{
// Find the player and remove from the current group
foreach ($this->groups as &$group) {
foreach ($group as $key => $player) {
if ($player->id == $playerId) {
unset($group[$key]);
break 2;
}
}
}
// Add the player to the new group
$this->groups[$newGroupIndex][] = $this->players->find($playerId);
// Force a re-render of the component
$this->emitSelf('playersGroupChanged');
}
}
And here's the updated view:
<div>
<x-buttons.button wire:click="open()">Groups</x-buttons.button>
<div x-data="{ isOpen: @entangle('isOpen') }">
<div x-show="isOpen" class="fixed inset-0 flex items-center justify-center bg-gray-800 bg-opacity-75">
<div class="bg-white p-6 rounded-lg shadow-lg">
<h2 class="text-xl font-bold mb-4">Popup Form</h2>
<form>
<!-- Add your form fields here -->
<div class="mb-4">
@foreach($groups as $groupIndex => $group)
<h3 class="text-lg font-bold">Group {{ $groupIndex + 1 }}</h3>
@foreach($group as $player)
<div class="mb-2">
<label class="block text-sm font-medium text-gray-700">{{ $player->present()->fullName() }}</label>
<select wire:change="changePlayerGroup({{ $player->id }}, $event.target.value)"
class="mt-1 block w-full">
@foreach($groups as $index => $grp)
<option value="{{ $index }}" @if($groupIndex == $index) selected @endif>
Group {{ $index + 1 }}: {{$groupIndex}}: {{$index}}
</option>
@endforeach
</select>
</div>
@endforeach
@endforeach
</div>
<div>
@foreach($groups as $groupIndex => $group)
<div><span>{{ $groupIndex }}:</span>
@foreach($group as $player)
<span>{{$player->id}},</span>
@endforeach
</div>
@endforeach
</div>
<div class="flex justify-end">
<button type="button" @click="isOpen = false"
class="bg-red-500 text-white px-4 py-2 rounded-md">Close
</button>
<button type="submit" class="bg-blue-500 text-white px-4 py-2 rounded-md ml-2">Submit</button>
</div>
</form>
</div>
</div>
</div>
</div>
This should ensure that the select boxes are updated correctly when a player is moved to a new group.