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

graememullins's avatar

Wire Click and If/else

Hi,

I have a Livewire Volt Class component for editing a client in a CRM, however when I add if statements around the save and cancel buttons they don't work, when the if statements are removed, whist all buttons are then shown, the functions work fine.

Livewire;

Blade

            @if(!$isEditing)
            <button wire:click="toggleEdit" class="inline-flex items-center px-4 py-2 bg-indigo-600 dark:bg-indigo-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-indigo-700 dark:hover:bg-indigo-900 active:bg-indigo-900 dark:active:bg-indigo-950 focus:outline-none focus:border-indigo-900 focus:ring-2 focus:ring-indigo-400 disabled:opacity-25 transition ease-in-out duration-150">
                Edit Client
            </button>
            @endif

            @if($isEditing)
            <button wire:click="save" class="inline-flex items-center px-4 py-2 bg-indigo-600 dark:bg-indigo-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-indigo-700 dark:hover:bg-indigo-900 active:bg-indigo-900 dark:active:bg-indigo-950 focus:outline-none focus:border-indigo-900 focus:ring-2 focus:ring-indigo-400 disabled:opacity-25 transition ease-in-out duration-150">
                Save
            </button>
            <button wire:click="toggleCancel" class="inline-flex items-center px-4 py-2 bg-gray-600 dark:bg-gray-700 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 dark:hover:bg-gray-800 active:bg-gray-900 dark:active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring-2 focus:ring-gray-400 disabled:opacity-25 transition ease-in-out duration-150">
                Cancel
            </button>
            @endif
            
            
    </div>
</div>

<div class="border-t border-gray-200 dark:border-gray-700 pt-4">
    <dl class="divide-y divide-gray-200 dark:divide-gray-700">
        @foreach (['main_switchboard' => 'Phone', 'email' => 'Email', 'address_1' => 'Address 1', 'address_2' => 'Address 2', 'city' => 'City', 'postcode' => 'Postcode', 'region' => 'Region', 'website' => 'Website'] as $field => $label)
            @if($client->$field)
                <div class="py-4 grid grid-cols-3 gap-4">
                    <dt class="text-sm font-extrabold text-gray-500 dark:text-gray-400">{{ $label }}</dt>
                    <dd class="col-span-2 text-sm text-gray-900 dark:text-gray-100">
                        @if($isEditing)
                            <label for="client-{{ $field }}" class="sr-only">{{ $label }}</label>
                            <input type="text" id="client-{{ $field }}" wire:model.defer="client.{{ $field }}" class="w-full px-3 py-2 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm focus:outline-none focus:ring-2 focus:ring-indigo-400 dark:bg-gray-900 dark:text-gray-100" value="{{ $client->$field }}">
                            @error("client.$field") <span class="text-red-500 dark:text-red-400">{{ $message }}</span> @enderror
                        @else
                            {{ $client->$field }}
                        @endif
                    </dd>
                </div>
            @endif
        @endforeach
    </dl>
</div>
0 likes
3 replies
graememullins's avatar

Here is the livewire;

use Livewire\Volt\Component; use App\Models\Client;

new class extends Component { public $client; public $isEditing = false; public $originalClient;

protected $rules = [
    'client.name' => 'required|string|max:255',
    'client.type' => 'nullable|string|max:255',
    'client.main_switchboard' => 'nullable|string|max:255',
    'client.email' => 'nullable|email|max:255',
    'client.address_1' => 'nullable|string|max:255',
    'client.address_2' => 'nullable|string|max:255',
    'client.city' => 'nullable|string|max:255',
    'client.postcode' => 'nullable|string|max:255',
    'client.region' => 'nullable|string|max:255',
    'client.website' => 'nullable|url|max:255',
];

public function mount(Client $client)
{
    $this->client = $client;
    $this->originalClient = $client->toArray(); // Save original state for cancel
}

public function toggleEdit()
{
    //dd('Edit client triggered');
    
    $this->isEditing = !$this->isEditing;
    if ($this->isEditing) {
        // Store the current values when entering edit mode
        $this->originalClient = $this->client->toArray();
    }
}

public function toggleCancel()
{
    //dd('Cancel client triggered');
    
    // Revert to original values when canceling edit
    $this->client = new Client($this->originalClient);
    $this->isEditing = false;
}

public function save()
{
    dd('Save client triggered');
    
    $this->validate(); // Validate inputs
    $this->client->save(); // Save client changes to database
    $this->isEditing = false; // Exit edit mode
}

};

LaryAI's avatar
Level 58

To address the issue you're facing with the Livewire component, it seems like the problem might be related to the state management of the $isEditing property. When using conditional rendering with Livewire, it's crucial to ensure that the state is being updated correctly and that the component re-renders as expected.

Here's a step-by-step solution to ensure your buttons and form fields work correctly:

  1. Ensure the Livewire Component is Set Up Correctly: Make sure your Livewire component has the necessary properties and methods. For example:

  2. Update the Blade Template: Ensure your Blade template correctly reflects the state of $isEditing. Here's the updated Blade template:

  3. Ensure Livewire is Properly Included: Make sure you have included Livewire scripts in your main layout file:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <!-- Other head elements -->
        @livewireStyles
    </head>
    <body>
        <!-- Your content -->
        @livewireScripts
    </body>
    </html>
    

By following these steps, you should be able to toggle between editing and viewing modes, and the buttons should work as expected. The key is to ensure that the $isEditing property is correctly managed and that the component re-renders when its state changes.

Chingy's avatar

Sounds like a DOM diffing issue. Generally Livewire doesnt like when HTML is appended to the DOM without expecting it.

For instance

<form>
// ...

<!-- Start -->
@if()
	<div>
		<div>
		</div>
	</div>
@endif
<!-- End -->
</form

Livewire, doesn't know that there is html to be expected where the <!-- Start --> is.

Some tricks that i do are

  1. Enclose blade directives inside divs
  2. Wire:keys to livewire components whether they are in a loop or not.
  3. Play around with x-show of Alpine. Much smoother UX

Please or to participate in this conversation.