I found a solution using Javascript "hooks", this is the PHP class for my toast alertor component:
<?php
namespace App\Livewire\Components;
use Illuminate\Support\Arr;
use Illuminate\Support\Carbon;
use Illuminate\View\View;
use Livewire\Attributes\On;
use Livewire\Component;
class Alertor extends Component
{
public array $alerts = [];
public function render(): View
{
return view('livewire.components.alertor');
}
#[On('alertor:alert')]
public function alert(string $type, string $message): void
{
$this->alerts[] = [
'type' => $type,
'message' => $message,
'timestamp' => Carbon::now()->timestamp,
];
}
public function dismiss(int $key): void
{
Arr::forget($this->alerts, $key);
}
}
This is the blade view of the component:
@php
use Illuminate\Support\Carbon;
@endphp
<div class="toast-container position-fixed bottom-0 end-0 mb-2 me-2"
@if (count($alerts) > 0) wire:poll.5000ms @endif>
@foreach ($alerts as $key => $alert)
<x-toast data-key="{{ $key }}"
wire:ignore.self=""
wire:key="alert-{{ $key }}">
<x-toast.header>
<strong class="me-auto">
@switch($alert['type'])
@case('success')
<span class="fas fa-fw fa-check-circle text-success"></span>
{{ __('Success') }}
@break
@case('error')
<span class="fas fa-fw fa-times-circle text-danger"></span>
{{ __('Error') }}
@break
@case('warning')
<span class="fas fa-fw fa-exclamation-circle text-warning"></span>
{{ __('Warning') }}
@break
@case('info')
<span class="fas fa-fw fa-info-circle text-info"></span>
{{ __('Notice') }}
@break
@default
<span class="fas fa-fw fa-info-circle text-info"></span>
{{ __('Notice') }}
@break
@endswitch
</strong>
<small class="me-1">
{{ Carbon::createFromTimestamp($alert['timestamp'])->diffForHumans(['options' => Carbon::JUST_NOW]) }}
</small>
<x-toast.close />
</x-toast.header>
<x-toast.body>
{{ $alert['message'] }}
</x-toast.body>
</x-toast>
@endforeach
</div>
@push('js')
<script>
document.addEventListener('livewire:initialized', () => {
Livewire.hook('morph.added', (element) => {
if (element.classList.contains('toast')) {
const toastObject = new bootstrap.Toast(element, {
delay: 60000
})
toastObject.show()
}
})
document.querySelector('.toast-container')
.addEventListener('hide.bs.toast', (event) => {
@this.call('dismiss', event.target.dataset.key)
})
})
</script>
@endpush
Using the hook, the new toast alert element is already added when the listener runs, so i can safely initialize the toast object from Bootstrap framework, this hook is very powerfull, hope this can help other developers who loves Laravel and Liewire. 😎