Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

muuucho's avatar
Level 11

One toggle works, the other doesn't

Can anyone see why toggleManageUpload() doesn't work, while toggleManageInvoice() does?

<?php
namespace App\Livewire;

use App\Models\User;
use Auth;
use Illuminate\Contracts\View\View;
use Jantinnerezo\LivewireAlert\LivewireAlert;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

class UsersList extends Component
{
    use LivewireAlert;
    use WithPagination;

    public ?User $user = null;
    #public Collection $users;
    public array $selected = [];
    #[Url]
    public string $sortColumn = 'users.name';  // Default col to sort
    #[Url]
    public string $sortDirection = 'asc'; // Default sort order
    public array $active = [];
    public array $admin = [];
    public array $upload = [];
    public array $invoice = [];
    public array $searchColumns = [
        'name' => '',
        'is_admin' => '',
        'email' => '',
        'is_active' => '',
        'manage_upload' => '',
        'manage_invoice' => '',
    ];
    public array $is_actives = [];
    public array $is_admins = [];
    public array $manage_uploads = [];
    public array $manage_invoices = [];       

    public function toggleManageUpload(int $userId): void
    {
        User::where('id', $userId)->update([
            'manage_upload' => $this->upload[$userId],
        ]);
    }

    public function toggleManageInvoice(int $userId): void
    {
        User::where('id', $userId)->update([
            'manage_invoice' => $this->invoice[$userId],
        ]);
    }
    
    public function render(): View
    {
        $usersQuery = User::query()
            ->select(['users.*']);
        foreach ($this->searchColumns as $column => $value) {
            if (!empty($value)) {
                $usersQuery
                    ->when($column === 'name', fn($query) => $query->where('users.'.$column, 'LIKE', '%'.$value.'%'))
                    ->when($column === 'email', fn($query) => $query->where('users.'.$column, 'LIKE', '%'.$value.'%'))		                    						 
                    ->when($column === 'manage_upload', fn($query) => $query->where('users.'.$column, '=', $value - 1))
                    ->when($column === 'manage_invoice', fn($query) => $query->where('users.'.$column, '=', $value - 1));
            }
        }
        $usersQuery->where('team_id', '=', auth()->user()->team_id);
        $usersQuery->orderBy($this->sortColumn, $this->sortDirection);
        $users = $usersQuery->get();
       
        $this->upload = $users->mapWithKeys(
            fn(User $item) => [$item['id'] => (bool) $item['manage_upload']]
        )->toArray();
        $this->invoice = $users->mapWithKeys(
            fn(User $item) => [$item['id'] => (bool) $item['manage_invoice']]
        )->toArray();
        return view('livewire.users-list', [
            'users' => $usersQuery->paginate(10)
        ]);
    }
}
<div>
       <div class="py-12">
        <div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
            <div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
                <div class="p-6 bg-white border-b border-gray-200">
                    <div class="mb-4">
                        <div class="mb-4">
                            <a href="{{ route('invitations.index') }}">
                                <x-button icon="o-eye" second>View Invites</x-button>
                            </a>
                        </div>
                    </div>
                    <div class="overflow-hidden overflow-x-auto mb-4 min-w-full align-middle sm:rounded-md">
                        <table class="min-w-full border divide-y divide-gray-200">
                            <thead>    
                                ...
                            </thead>
                            <tbody class="bg-white divide-y divide-gray-200 divide-solid">
                            @foreach($users as $user)
                                <tr class="bg-white" wire:key="{{ $user->id }}">                           
                                                <td class="px-6">
                                        {{ $upload[$user->id] ? $upload[$user->id] : '0'}}
                                        <div class="inline-block relative mr-2 w-10 align-middle transition duration-200 ease-in select-none">
                                            <input wire:model="upload.{{ $user->id }}" wire:click="toggleManageUpload({{ $user->id }})" type="checkbox" name="toggle3"
                                                   id="{{ $loop->index.$user->id.'3' }}"
                                                   class="block absolute w-6 h-6 bg-white rounded-full border-4 appearance-none cursor-pointer focus:outline-none toggle-checkbox"
                                                    {{ Auth::user()->is_admin ? '' : 'disabled' }}
                                            />
                                            <label for="{{ $loop->index.$user->id.'3' }}"
                                                   class="block overflow-hidden h-6 bg-gray-300 rounded-full cursor-pointer toggle-label"></label>
                                        </div>
                                    </td>
                                    <td class="px-6">
                                        {{ $invoice[$user->id] ? $invoice[$user->id] : '0'}}
                                        <div class="inline-block relative mr-2 w-10 align-middle transition duration-200 ease-in select-none">
                                            <input wire:model="invoice.{{ $user->id }}" wire:click="toggleManageInvoice({{ $user->id }})" type="checkbox" name="toggle4"
                                                   id="{{ $loop->index.$user->id.'4' }}"
                                                   class="block absolute w-6 h-6 bg-white rounded-full border-4 appearance-none cursor-pointer focus:outline-none toggle-checkbox"
                                                    {{ Auth::user()->is_admin ? '' : 'disabled' }}
                                            />
                                            <label for="{{ $loop->index.$user->id.'4' }}"
                                                   class="block overflow-hidden h-6 bg-gray-300 rounded-full cursor-pointer toggle-label"></label>
                                        </div>
                                    </td>
                                    <td></td>
                                </tr>
                            @endforeach
                            </tbody>
                        </table>                        
                    </div>                   
                </div>
            </div>
        </div>
    </div>
</div>
protected $fillable = [
        'team_id',
        'is_active',
        'is_admin',
        'manage_upload',
        'manage_invoice',
        'name',
        'email',
        'password',
    ];
public function up()
    {
        Schema::create('users', function (Blueprint $table){
            $table->id();
            $table->unsignedBigInteger('team_id')->nullable();
            $table->boolean('is_active')->default(false);
            $table->boolean('is_admin')->default(false);
            $table->boolean('manage_upload')->default(false);
            $table->boolean('manage_invoice')->default(false);
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamp('email_verified_at')->nullable();
            $table->string('password');
            $table->rememberToken();
            $table->timestamps();
        });
    }
0 likes
8 replies
LaryAI's avatar
Level 58

The issue with the toggleManageUpload() method not working while toggleManageInvoice() does could be due to several reasons. Let's go through a few potential issues and solutions:

  1. Initialization of the upload array: Ensure that the upload array is properly initialized in the render() method, similar to how the invoice array is initialized.

  2. Binding the upload array to the checkbox: Make sure that the wire:model directive is correctly binding the upload array to the checkbox input.

  3. Updating the upload array correctly: Ensure that the upload array is being updated correctly when the checkbox is clicked.

Let's review the code and make sure everything is set up correctly.

Updated Code

Component Class

namespace App\Livewire;

use App\Models\User;
use Auth;
use Illuminate\Contracts\View\View;
use Jantinnerezo\LivewireAlert\LivewireAlert;
use Livewire\Attributes\Url;
use Livewire\Component;
use Livewire\WithPagination;

class UsersList extends Component
{
    use LivewireAlert;
    use WithPagination;

    public ?User $user = null;
    public array $selected = [];
    #[Url]
    public string $sortColumn = 'users.name';  // Default col to sort
    #[Url]
    public string $sortDirection = 'asc'; // Default sort order
    public array $active = [];
    public array $admin = [];
    public array $upload = [];
    public array $invoice = [];
    public array $searchColumns = [
        'name' => '',
        'is_admin' => '',
        'email' => '',
        'is_active' => '',
        'manage_upload' => '',
        'manage_invoice' => '',
    ];
    public array $is_actives = [];
    public array $is_admins = [];
    public array $manage_uploads = [];
    public array $manage_invoices = [];       

    public function toggleManageUpload(int $userId): void
    {
        User::where('id', $userId)->update([
            'manage_upload' => $this->upload[$userId],
        ]);
    }

    public function toggleManageInvoice(int $userId): void
    {
        User::where('id', $userId)->update([
            'manage_invoice' => $this->invoice[$userId],
        ]);
    }
    
    public function render(): View
    {
        $usersQuery = User::query()
            ->select(['users.*']);
        foreach ($this->searchColumns as $column => $value) {
            if (!empty($value)) {
                $usersQuery
                    ->when($column === 'name', fn($query) => $query->where('users.'.$column, 'LIKE', '%'.$value.'%'))
                    ->when($column === 'email', fn($query) => $query->where('users.'.$column, 'LIKE', '%'.$value.'%'))		                    						 
                    ->when($column === 'manage_upload', fn($query) => $query->where('users.'.$column, '=', $value - 1))
                    ->when($column === 'manage_invoice', fn($query) => $query->where('users.'.$column, '=', $value - 1));
            }
        }
        $usersQuery->where('team_id', '=', auth()->user()->team_id);
        $usersQuery->orderBy($this->sortColumn, $this->sortDirection);
        $users = $usersQuery->get();
       
        $this->upload = $users->mapWithKeys(
            fn(User $item) => [$item['id'] => (bool) $item['manage_upload']]
        )->toArray();
        $this->invoice = $users->mapWithKeys(
            fn(User $item) => [$item['id'] => (bool) $item['manage_invoice']]
        )->toArray();
        return view('livewire.users-list', [
            'users' => $usersQuery->paginate(10)
        ]);
    }
}

Blade Template

<div>
    <div class="py-12">
        <div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
            <div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
                <div class="p-6 bg-white border-b border-gray-200">
                    <div class="mb-4">
                        <div class="mb-4">
                            <a href="{{ route('invitations.index') }}">
                                <x-button icon="o-eye" second>View Invites</x-button>
                            </a>
                        </div>
                    </div>
                    <div class="overflow-hidden overflow-x-auto mb-4 min-w-full align-middle sm:rounded-md">
                        <table class="min-w-full border divide-y divide-gray-200">
                            <thead>    
                                ...
                            </thead>
                            <tbody class="bg-white divide-y divide-gray-200 divide-solid">
                            @foreach($users as $user)
                                <tr class="bg-white" wire:key="{{ $user->id }}">                           
                                    <td class="px-6">
                                        {{ $upload[$user->id] ? $upload[$user->id] : '0'}}
                                        <div class="inline-block relative mr-2 w-10 align-middle transition duration-200 ease-in select-none">
                                            <input wire:model="upload.{{ $user->id }}" wire:click="toggleManageUpload({{ $user->id }})" type="checkbox" name="toggle3"
                                                   id="{{ $loop->index.$user->id.'3' }}"
                                                   class="block absolute w-6 h-6 bg-white rounded-full border-4 appearance-none cursor-pointer focus:outline-none toggle-checkbox"
                                                    {{ Auth::user()->is_admin ? '' : 'disabled' }}
                                            />
                                            <label for="{{ $loop->index.$user->id.'3' }}"
                                                   class="block overflow-hidden h-6 bg-gray-300 rounded-full cursor-pointer toggle-label"></label>
                                        </div>
                                    </td>
                                    <td class="px-6">
                                        {{ $invoice[$user->id] ? $invoice[$user->id] : '0'}}
                                        <div class="inline-block relative mr-2 w-10 align-middle transition duration-200 ease-in select-none">
                                            <input wire:model="invoice.{{ $user->id }}" wire:click="toggleManageInvoice({{ $user->id }})" type="checkbox" name="toggle4"
                                                   id="{{ $loop->index.$user->id.'4' }}"
                                                   class="block absolute w-6 h-6 bg-white rounded-full border-4 appearance-none cursor-pointer focus:outline-none toggle-checkbox"
                                                    {{ Auth::user()->is_admin ? '' : 'disabled' }}
                                            />
                                            <label for="{{ $loop->index.$user->id.'4' }}"
                                                   class="block overflow-hidden h-6 bg-gray-300 rounded-full cursor-pointer toggle-label"></label>
                                        </div>
                                    </td>
                                    <td></td>
                                </tr>
                            @endforeach
                            </tbody>
                        </table>                        
                    </div>                   
                </div>
            </div>
        </div>
    </div>
</div>

Key Points to Check

  1. Initialization: Ensure that both upload and invoice arrays are initialized correctly in the render() method.
  2. Binding: Verify that the wire:model directive is correctly binding the upload and invoice arrays to the respective checkbox inputs.
  3. Update Logic: Ensure that the toggleManageUpload and toggleManageInvoice methods are correctly updating the database.

By ensuring these points, both toggle methods should work as expected.

Snapey's avatar

bear in mind your id does not have any separators

id="{{ $loop->index.$user->id.'4' }}"

loop 11, user 1 (1114) is indistinguishable from loop 1, user 11 (1114)

muuucho's avatar
Level 11

@snapey Thanks for pointing that out. Anyway, I dubble checked Larrys suggestions and didn't found the problem.

muuucho's avatar
Level 11

@Snapey Console is empty. I now have underscore separator for id and label. Please note that I echo out {{ $upload[$user->id] ? $upload[$user->id] : '0'}} and {{ $invoice[$user->id] ? $invoice[$user->id] : '0'}} Invoice is toggling between 0 and 1 both frontend and in the db as expected, while Upload keeps it's value from the db both frontend and in the db (The toggle icon itself toggels but not the echoed out $upload[$user->id]).

Snapey's avatar

@muuucho From Livewire docs;

The "upload" method is reserved

Notice the above example uses a "save" method instead of an "upload" method. This is a common "gotcha". The term "upload" is reserved by Livewire. You cannot use it as a method or property name in your component.

https://livewire.laravel.com/docs/uploads

2 likes
muuucho's avatar
Level 11

@Snapey IMO, Livewire and any other framework should have an easily found list or reserved words. Just like PHP has. It should have saved us lots of time this week.

Please or to participate in this conversation.