I am trying to make a component to show a userProfile with "Show mode" and "Edit Mode". Initially you enter in "Show Mode" and see -Edit- and -Back- buttons. If you click on Edit, the component changes to "Edit mode", replacing the data for input elements, and the buttons for -Save- and -Cancel-.
The buttons toggle the isEditing
value between true
and false
, and the component switches correctly between modes. However, I’m facing a situation that’s driving me crazy:
I start in "Show mode."
I press the Edit button, and it switches to "Edit mode."
I press the Cancel button, and it returns to "Show mode."
I press the Edit button again, but this time it doesn’t trigger anything.
I am using Laravel 11 and Livewire 3
This are my component code:
This is my Livewire component:
<?php
namespace App\Livewire;
use Livewire\Component;
use App\Models\User;
class UserProfile extends Component
{
public User $usuario; // Cambia 'user' por 'usuario' para que coincida con el parámetro
public bool $isEditing = false;
protected $rules = [
'usuario.name' => 'required|string|max:255',
'usuario.email' => 'required|email|max:255|unique:users,email',
];
protected $queryString = [
'isEditing',
];
public function mount($userId, $isEditing = false)
{
$this->usuario = User::findOrFail($userId);
}
public function edit()
{
$this->isEditing = true;
}
public function cancel()
{
$this->isEditing = false;
$this->usuario->refresh();
}
public function save()
{
$this->validate();
$this->usuario->save();
$this->isEditing = false;
session()->flash('success', 'User updated successfully!');
}
public function render()
{
return view('livewire.user-profile');
}
}
This is my component view:
<div>
<!-- Mensaje de confirmación -->
@if (session()->has('message'))
<div class="mb-4 bg-green-100 text-green-800 px-4 py-2 rounded">
{{ session('message') }}
</div>
@endif
<!-- Ficha de usuario -->
@if ($isEditing)
<div class="mb-6">
<h2 class="text-lg font-semibold text-red-500 dark:text-gray-100">
{{ __('_UserProfile.TitleEdit') }}
</h2>
</div>
@endif
<div class="space-y-4">
<!-- Nombre -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('_UserManagement.Name') }}</label>
@if ($isEditing)
<input type="text"
wire:model="usuario.name"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
@error('usuario.name') <span class="text-red-600 text-sm">{{ $message }}</span> @enderror
@else
<p class="mt-1 text-gray-800 dark:text-gray-200">{{ $usuario->name }}</p>
@endif
</div>
<!-- Email -->
<div>
<label class="block text-sm font-medium text-gray-700 dark:text-gray-300">{{ __('_UserManagement.Email') }}</label>
@if ($isEditing)
{{$usuario->email}}
<input type="email"
wire:model="usuario.email"
class="mt-1 block w-full rounded-md border-gray-300 shadow-sm focus:border-indigo-500 focus:ring-indigo-500 sm:text-sm">
@error('usuario.email') <span class="text-red-600 text-sm">{{ $message }}</span> @enderror
@else
<p class="mt-1 text-gray-800 dark:text-gray-200">{{ $usuario->email }}</p>
@endif
</div>
</div>
<!-- Botones -->
<div class="mt-6 flex space-x-2">
@if ($isEditing)
<button wire:click="save" class="px-4 py-2 bg-blue-600 text-white text-sm rounded hover:bg-blue-700">
{{ __('_Save') }}
</button>
<button wire:click="cancel" class="px-4 py-2 bg-gray-600 text-white text-sm rounded hover:bg-gray-700">
{{ __('_Cancel') }}
</button>
@else
<button wire:click="edit" class="px-4 py-2 bg-indigo-600 text-white text-sm rounded hover:bg-indigo-700">
{{ __('_Edit') }}
</button>
<a href="{{ route('users.index') }}" class="px-4 py-2 bg-red-600 text-white text-sm rounded hover:bg-gray-700">
{{ __('_Back') }}
</a>
@endif
</div>
</div>
It's weird this only fails at second time? Maybe some conflict that I can't see.
I tried some things:
I’ve tried add this to my edit and cancel functions:
$this->dispatch('$refresh');
because I read that this help to force the refresh of the component in the DOM. Not working
I’ve tried adding logs to both the edit
and cancel
methods. The edit
method logs correctly when it’s triggered in step 2, but in step 4, it seems like nothing happens—the method doesn’t execute.
I tried using isEditing as bool or without explicit type
The issue I was experiencing was caused by a conflict due to using Laravel Breeze, which includes Alpine.js by default. Livewire also initializes its own instance of Alpine.js. While this doesn't always cause conflicts across the app, in my case, it was the root of the problem.
To resolve it, I removed the Alpine.js initialization from resources/js/app.js
. Here's the updated file:
import './bootstrap';
/*
import Alpine from 'alpinejs';
window.Alpine = Alpine;
Alpine.start();
*/
Changing this I get this finally working. Thanks to all for the help.