A good solution is to use websockets. If you use pusher with laravel echo, it's quite easy to get working https://laravel.com/docs/8.x/broadcasting#pusher-channels
Show new database notifications to users without refreshing the page
I've been working on some way to show new notifications to the users without the need to refresh the page (I've a notification button in my navbar that retrieves new notifications every time a page is loaded). This is what I've now (I'm a total noob in this area):
profile_notification.blade.php:
<div x-data="notifications()"
x-init="retrieveNotificationData()"
@retrievenotificationsdata.window="setNotificationsValues($event.detail.res_notifications)"
@retrievenewunreadnotificationsdata.window="updateNewNotifications($event.detail.res_new_unread_data)">
@include('layouts.menu_partials.notification_button')
<div class="ml-3 relative">
@include('layouts.menu_partials.notification_content')
</div>
</div>
notifications.js:
function notifications() {
return {
notification_count_indicator: 0,
notifications: [],
retrieveNotificationData: function() {
window.livewire.emit('retrieve_notifications_data');
this.notificationsListener(); /* This function calls a php method every x time to check if there are new notifications and if so retrieve them to add them to the notifications array */
},
setNotificationsValues: function(res) {
this.notifications = [];
res[0].forEach(notif => {
this.notifications.push(notif)
});
this.notification_count_indicator = res[1];
},
notificationsListener: function() {
setInterval(() => {
window.livewire.emit('check_notifications', { counter: this.notification_count_indicator });
}, 3000);
},
updateNewNotifications: function(res) {
this.notification_count_indicator += res[1];
res[0].forEach(noti => {
var exists = false;
for(var i = 0; i < notifications.length; i++) {
if(notifications[i].id == noti.id)
exists = true;
}
if(!exists)
this.notifications.unshift(noti);
});
this.notification_alert = true;
this.unread_notification();
},
}
}
profileNotificationController.php
<?php
namespace App\Http\Livewire;
use App\Models\Servicio;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Session;
use Livewire\Component;
class Navigation extends Component
{
protected $listeners = ['retrieve_notifications_data' => 'retrieveNotificationsData',
'check_notifications' => 'checkNotifications'];
public function retrieveNotificationsData_odm_imp() {
if(Auth::check()) {
$this->dispatchBrowserEvent('retrievenotificationsdata', ['res_notifications' => [array_slice(Auth::user()->unreadNotifications->merge(Auth::user()->Notifications)->toArray(), 0, 3, true), Auth::user()->unreadNotifications->count()]]);
} else {
$this->dispatchBrowserEvent('retrievenotificationsdata', ['res_notifications' => [[], 0]]);
}
}
public function checkNotifications_odm_imp($counter) {
$diff = Auth::user()->unreadNotifications->count() - $counter['counter'];
if($diff > 0) {
$newUnreadNotifications = Auth::user()->notifications()->latest()->take($diff)->get()->toArray();
$this->dispatchBrowserEvent('retrievenewunreadnotificationsdata', ['res_new_unread_data' => [$newUnreadNotifications, $diff]]);
}
}
}
What I do is that I send every 3 seconds the number of elements of the current notification array to php and compare it with the number of notifications in the database. If the difference between them is more than 0 I retrieve the last notifications of the database (based in the difference, of course) and then I send them as an event.
I know that's not even close to be an optimal solution and a really risky one. So I'm wondering what's the best way to retrieve the new notifications so I can add them to an array via Javascript (and Alpine JS in this case) without the need to have a constant communication between front end and back end
Please or to participate in this conversation.