I have a UserShow
component which shows the user's data (name, email, etc.) and also the actions he made in the site via relations (messages written, likes given, etc.). Now I want to allow user to change some of his data (name, email, etc.), so I wrote another component called UserEdit
here is the form, validation, etc. It's working fine.
Since I'm using Livewire/Alpine I have some logic like
<div x-data="{ isEditing = @entangle('isEditing) }">
<section x-show="!isEditing" />
...All user data...
<button x-on:click="isEditing=true">
<section>
<section x-show="isEditing">
<livewire:user.user-edit :user="$user" />
</section>
</div>
So this works - it opens the component where the user will edit his data. In the component by the form's end, I have two buttons:
<div>
<button type="submit">update</x-gui.button>
<button type="button" wire:click="canceled">Cancel</button>
</div>
The canceled function in the component is:
public function canceled() {
Log::info('Canceling Edit');
$this->emitUp('canceled');
}
Now, in the parent element I have the listeners ans the function defined as:
protected $listeners = ['canceled' => 'restart'];
public function restart() {
Log::info('canceled received');
}
When I click the cancel method in the component, I see the first log "Canceling Edit", but I don't see the "canceled received" message
Am I doing something wrong? How do I know if the "canceled" event is even being fired?
$emit('canceled')
from the button, but same thing without the log happensI found what happened, and it was a very strange behaivour, so it tooks ages to debug.
The problem in this very specific component is that it was displaying all the messages inside a foreach, like:
<div x-data="{ isEditing = @entangle('isEditing) }">
<section x-show="!isEditing" />
...All user data... <=== PRECISELY HERE!!!
<button x-on:click="isEditing=true">
<section>
<section x-show="isEditing">
<livewire:user.user-edit :user="$user" />
</section>
</div>
The all user data had a @foreach()
that was rendering another component:
@foreach($user->messages as $message)
<livewire:message-card :message="$message" />
@endforeach
The problem was this livewire component wasn't being keyed, and this caused all kind of strange things to happen, chaging the line as below, solved the problem
<livewire:message-card :message="$message" :key="$message->id" />
So, the cautionary tale is: Always key your components inside a loop, even when they are just for displaying information, and not to be acted upon them