The Problem
Im trying to build a custom notification banner that will trigger instantly on top of the screen, whenever its triggered. The session() doesn't work the way I want it to, so I can't use it.
I believe the component is simply not re-rendering. I have put a /Debugbar::addMessage() in the components and all of the variables are set correctly, there is a REQUEST each time I click the button and the data changes. However, the view doesn't. The :class is not applied at all, the banner has no background color (The element exists in the HTML, I checked in Chrome, it just doesn't want to update.
The Code
I have a Helper:
class NotifyUser
{
public static function sendBanner(string $message, int $type = 2, int $timeout = 3): void
{
Banner::notify($message, $type, ($timeout *1000));
}
}
Then I have a Banner Livewire component:
namespace App\Livewire\Notifications;
use Livewire\Component;
class Banner extends Component
{
public $message, $type, $timeout, $visible = false;
public function render()
{
return view('livewire.notifications.banner');
}
public static function notify($message, $type, $timeout): void
{
$instance = new static();
if($instance->_showNotification($message, $type, $timeout)) {
\Debugbar::addMessage($instance);
\Debugbar::addMessage($message);
\Debugbar::addMessage($type); //It prints the message and type = 1
$instance->dispatch('send-notification');
}
}
private function _showNotification($message, $type, $timeout): bool
{
$this->message = $message;
$this->type = $type;
$this->timeout = $timeout;
$this->visible = true;
return isset($this->message);
}
}
The view for the component:
<div class="w-full flex justify-center">
<div x-data="{ show: $wire.entangle('visible'), type: $wire.entangle('type'), timeout: $wire.entangle('timeout') }"
x-show="show"
x-init="if (show) {
setTimeout(() => { show = false }, timeout);
}
"
x-on:send-notification="console.log('Sending notification')"
class="z-50 fixed top-0 m-4 text-white p-4 rounded w-5/6"
:class="{'bg-red-500': type === 0, 'bg-green-500 ': type === 1, 'bg-blue-500 ': type === 2}">
{{ $message }}
</div>
</div>
Its placed in the default layout app.blade.php like:
</head>
<body class="font-sans antialiased">
{{--<x-banner />--}}
@livewire('notifications.banner')
Its called like:
<button wire:click="sendNotification(true)"> Test</button>
public function sendNotification($isSuccess): void
{
if($isSuccess) NotifyUser::sendBanner(__('flashes.object.updated'), 1);
}
Livewire
The more I work in Livewire, the more I realize how much it sucks for learning, because it makes no god damn sense sometimes and its really frustrating to work in it. Maybe I should've went with Vue. The documentation says I can do x-on:send-notification="console.log('Sending notification')" and AlpineJS would work, so when I do this, I dont see a 'Sending notification' in the console, eventhough a new request was made. The result from \Debugbar::addMessage($instance); is:
App\Livewire\Notifications\Banner {#1694 ▼
#__id: null
#__name: null
#listeners: []
#attributes: ? Livewire\Features\SupportAttributes\AttributeCollection
#withValidatorCallback: null
#rulesFromOutside: []
#messagesFromOutside: []
#validationAttributesFromOutside: []
+message: "Anzeige aktualisiert!"
+type: 1
+timeout: 3000
+visible: true
}
The documentation also says I can bind the Livewire and AlpineJS variables, however it doesnt work.