I ran into a problem, using a custom Notification Model (not the Laravel standard one).
In my Controller, I'm getting all Notifications and save them to a variable.
After that, I'm updating all Notifications and set a read_at
datetime.
public function index($showRead = null)
{
$user = auth()->user();
$notifications = $user->notifications()->latest()->paginate(10);
$view = view('notification.index',['notifications'=>$notifications])->render();
Notification::where('id_user',$user->id)->update(['read_at'=>now()]);
return $view;
}
Problem:
The $notifications
Collection does contain read_at NULL
entries, as I fetch the data in the 2nd line.
But somehow, the update refreshes the Rendered View as well.
Can I prevent that somehow? I want to display unread Notifications on the first page request, and in the following requests, they should have the timestamp.
CodePudding user response:
Use where()
condition in this query for fetch unread notifications: $notifications = $user->notifications()->where('read_at', Null)->orderBy('created_at', 'DESC')->paginate(10);
Solutions for update Notification after read:
Solution 1:
Store your unread Notifications into Laravel Collections and compact to the view: $notifications = $user->notifications()->latest()->paginate(10);
Solution 2:
Or run this query in your view blade Notification::where('id_user',$user->id)->update(['read_at'=>now()]);
Solution 3:
When the user will access the Notification view blade, send an AJax request to update notifications.
CodePudding user response:
you can create a builder on notifications ( do not use get), then clone the first builder into another variable, after that you can update the cloned builder and get the collection from original.
$notifsBuilder1= $user->notifications();
$notifsBuilder2 = clone $notifsBuilder1;
$notifs = $notifsBuilder1->latest()->paginate(10);
$notifsBuilder2->update(['read_at'=>now()])
CodePudding user response:
Easiest way to do this kind of operation, is to have your front-end send an api request to your controller to make a certain notification read. You can do that using:
class NotificationsController extends Controller{
public function index(Request $request, $showRead = null){
$user = auth()->user();
$notifications = Notification::where('user_id', $user->getKey())->latest()->orderBy('created_at')->paginate(10);
return view('notifications.index', compact('notifications'));
}
public function markAsRead(Notification $notification){
$done = $notification->forceFill(['read_at' => now()]);
return compact('done');
}
}
then inside of your front-end if you are using VueJs i suppose, then you can use this (don't worry you can also lookup for the matching things if your not):
Inside of your Vue Component use axios library to handle requests, and ziggy library for your routes:
let axios = require('axios');
let notifications = [];
let getNotifications = async () => {
return axios.get(route('notifications.index')).then(res => {
notifications = res.data.notifications;
});
}
let markNotificationAsRead = (notification_id) => {
axios.get(route('notification.read', ['notification' => notification_id]));
}
getNotifications();
for(let i = 0; i < notifications.length; i ){
markNotificationAsRead(notifications[notification].id);
}
This way all your notifications are handled through your api and your api only, because imaging your user asks for the notifications but then cancels the request just before you handed him his response, he would miss those actually.