AlpineJS x-for not running after x-data update - laravel

I am running into a very strange issue where I have a chatroom that should update whenever a new message is posted. Instead when I add a new message the x-data is getting updated and I can see the message there but the x-for doesnt seem to run and it never appears on the frontend. Then when I enter another message the previous message shows up on the frontend but the latest message does not show even though the x-data has been updated to reflect it.
Here is the code below:
<div
x-data="{{ json_encode(['messages' => $messages, 'messageBody' => '']) }}"
x-init="
Echo.join('chat.2')
.listen('ChatSent', (e) => {
#this.call('incomingMessage', e)
console.log(e)
})
">
<div
class="wow fadeInUp mb-10 rounded-md bg-light-bg dark:bg-dark"
data-wow-delay="0s"
>
<h3
class="border-b border-body-color border-opacity-10 py-4 px-8 text-lg font-semibold text-black dark:border-white dark:border-opacity-10 dark:text-white"
>
Chat
</h3>
<div id="chat-window" class="relative w-full p-3 overflow-y-auto h-[14rem]">
<ul class="space-y-2">
<template
x-for="message in messages"
:key="message.id"
>
<div>
<template x-if="message.user_id == {{ Auth::user()->id }}">
<li class="flex justify-end">
<div class="relative max-w-xl px-4 py-2 text-black dark:text-white bg-gray-100 dark:bg-black rounded shadow">
<span class="block" x-text="message.body"></span>
</div>
</li>
</template>
<template x-if="message.user_id != {{ Auth::user()->id }}">
<li class="flex justify-start">
<div class="relative max-w-xl px-4 py-2 text-black dark:text-white bg-blue-100 dark:bg-[#1e2a78] rounded shadow">
<span class="block" x-text="message.body"></span>
</div>
</li>
</template>
</div>
</template>
</ul>
</div>
<div class="flex items-center justify-between w-full p-3 border-t border-gray-300">
<input
#keydown.enter="
#this.call('sendMessage', messageBody)
messageBody = ''
"
x-model="messageBody"
type="text"
placeholder="Message"
class="block w-full py-2 pl-4 mx-3 bg-gray-100 dark:bg-black rounded-full outline-none focus:text-gray-700 dark:focus:text-white dark:text-white"
name="message" required />
<button
#click="
#this.call('sendMessage', messageBody)
messageBody = ''
">
<svg class="w-5 h-5 text-black dark:text-white origin-center transform rotate-90" xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 20 20" fill="currentColor">
<path
d="M10.894 2.553a1 1 0 00-1.788 0l-7 14a1 1 0 001.169 1.409l5-1.429A1 1 0 009 15.571V11a1 1 0 112 0v4.571a1 1 0 00.725.962l5 1.428a1 1 0 001.17-1.408l-7-14z" />
</svg>
</button>
</div>
#error('messageBody')
<div class="w-full p-2 text-center">
<span class="text-red-500">Message is required!</span>
</div>
#enderror
</div>
<div
class="wow fadeInUp mb-10 rounded-md bg-light-bg dark:bg-dark"
data-wow-delay="0s">
<h3
class="border-b border-body-color border-opacity-10 py-4 px-8 text-lg font-semibold text-black dark:border-white dark:border-opacity-10 dark:text-white"
>
Active Players
</h3>
<ul class="flex flex-wrap py-6 px-8">
#forelse($here as $authData)
<li>
<a
href="javascript:void(0)"
class="text-body-color-3 mr-3 mb-3 inline-flex items-center justify-center rounded-full border-[.5px] border-body-color bg-body-color bg-opacity-10 py-2 px-4 hover:border-primary hover:bg-primary hover:text-white dark:border-[#363D68] dark:bg-[#272E5C] dark:text-white dark:hover:border-primary dark:hover:bg-primary dark:hover:text-white"
>
{{ $authData['name'] }}
</a>
</li>
#empty
#endforelse
</ul>
</div>
</div>
I figure it has to be something simple I am missing and hopefully someone can point me in the right direction.
EDIT to include Livewire code:
<?php
namespace App\Http\Livewire;
use App\Events\ChatSent;
use App\Models\Chat;
use App\Models\Games;
use Illuminate\Support\Facades\Auth;
use Livewire\Component;
class Chatbox extends Component
{
public $game_id, $game, $chats;
public $here = [];
public $messages = [];
public function getListeners()
{
$game_id = $this->game_id;
return [
"echo-presence:chat.{$game_id},here" => 'here',
"echo-presence:chat.{$game_id},joining" => 'joining',
"echo-presence:chat.{$game_id},leaving" => 'leaving',
];
}
public function render()
{
return view('games.components.chatbox');
}
public function mount()
{
$this->game = Games::find($this->game_id);
$this->messages = Chat::
where('games_id', $this->game_id)
->with('user')
->latest()
->limit(30)
->get()
->reverse()
->values()
->toArray();
}
public function sendMessage($body)
{
if (! $body) {
$this->addError('messageBody', 'Message body is required.');
return;
}
$message = Auth::user()->chats()->create([
'body' => $body,
'games_id' => $this->game_id,
]);
$message->load('user');
broadcast(new ChatSent($message, $this->game))->toOthers();
$myMessage = $message->toArray();
$this->dispatchBrowserEvent('update-chat');
array_push($this->messages, $myMessage);
}
/**
* #param $message
*/
public function incomingMessage($message)
{
// get the hydrated model from incoming json/array.
$message = Chat::with('user')->find($message['id']);
array_push($this->messages, $message);
$this->dispatchBrowserEvent('update-chat');
}
/**
* #param $data
*/
public function here($data)
{
$this->here = $data;
}
/**
* #param $data
*/
public function leaving($data)
{
$here = collect($this->here);
$firstIndex = $here->search(function ($authData) use ($data) {
return $authData['id'] == $data['id'];
});
$here->splice($firstIndex, 1);
$this->here = $here->toArray();
}
/**
* #param $data
*/
public function joining($data)
{
$this->here[] = $data;
}
}

Related

Laravel9 FullCalendar6 LiveWire EditEventModal not UPDATING event

I've managed to convert over most of the FullCalendar 6 JS into a Laravel Livewire component. I've created a Modal that, when an empty date is clicked on the calendar, creates an event. I've similarly constructed an EditEventModal that allows the created event data to update the database...However, it's not actually UPDATING the data, it DUPLICATES the event with the updated data and doesn't destroy the old event. Suggestions?
Here's my Livewire Calendar View:
<style>
#calendar-container {
display: grid;
grid-template-columns: 200px 1fr;
padding: 20px;
}
#events {
grid-column: 1;
}
#calendar {
grid-column: 2;
height: 700px;
}
.dropEvent {
background-color: DodgerBlue;
color: white;
padding: 5px 16px;
margin-bottom: 10px;
text-align: center;
display: inline-block;
font-size: 16px;
border-radius: 4px;
cursor:pointer;
}
</style>
<div>
#include('livewire.eventmodal')
<div>
<!-- sidebar -->
<div id="calendar-container" wire:ignore>
<div id="events">
<div data-event='{"title":"Evénement A"}' class="dropEvent">Event One Drag</div>
<div data-event='{"title":"Evénement B"}' class="dropEvent">Event Two Draggable</div>
</div>
<div id="calendar"></div>
</div>
</div>
<!-- start add event modal -->
<div id="AddEventModal" class="modal fade">
<form action="/events" method="POST">
{{csrf_field()}}
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4>Add Event</h4>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span> <span class="sr-only">close</span></button>
</div>
<!-- <form wire:submit.prevent="saveEvent"> -->
<div id="modalBody" class="modal-body">
<div class="bg-white sm:p-6">
<label for="title" class="block font-medium text-sm text-gray-700">Title</label>
<input type="text" name="title" id="title" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('title', '') }}" />
#error('title')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="acronym" class="block font-medium text-sm text-gray-700">Acronym</label>
<input type="text" name="acronym" id="acronym" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('acronym', '') }}" />
#error('acronym')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="city" class="block font-medium text-sm text-gray-700">City</label>
<input type="text" name="city" id="city" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('city', '') }}" />
#error('city')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="venue" class="block font-medium text-sm text-gray-700">Venue</label>
<input type="text" name="venue" id="venue" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('venue', '') }}" />
#error('venue')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="value" class="block font-medium text-sm text-gray-700">Value</label>
<input type="text" name="value" id="value" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('value', '') }}" />
#error('value')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="start" class="block font-medium text-sm text-gray-700">Start Date</label>
<input type="date" name="start" id="start" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('start', '') }}" />
#error('start')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="end" class="block font-medium text-sm text-gray-700">End Date</label>
<input type="date" name="end" id="end" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('end', '') }}" />
#error('end')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button type="submit" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#AddEventModal" id="submit">Save</button>
</div>
</form>
</div>
</div>
</div>
<!--end add event modal -->
<!--start edit event modal -->
<div id="EditEventModal" class="modal fade" role="dialog">
<form action="/events" method="POST">
{{csrf_field()}}
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h4>Edit Event</h4>
<button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">×</span> <span class="sr-only">close</span></button>
</div>
<form wire:submit.prevent="saveEvent">
<div id="modalBody" class="modal-body">
<div class="bg-white sm:p-6">
<label for="title" class="block font-medium text-sm text-gray-700">Title</label>
<input type="text" name="title" id="title" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('title', '') }}" />
#error('title')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="acronym" class="block font-medium text-sm text-gray-700">Acronym</label>
<input type="text" name="acronym" id="acronym" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('acronym', '') }}" />
#error('acronym')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="city" class="block font-medium text-sm text-gray-700">City</label>
<input type="text" name="city" id="city" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('city', '') }}" />
#error('city')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="venue" class="block font-medium text-sm text-gray-700">Venue</label>
<input type="text" name="venue" id="venue" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('venue', '') }}" />
#error('venue')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="value" class="block font-medium text-sm text-gray-700">Value</label>
<input type="text" name="value" id="value" type="text" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('value', '') }}" />
#error('value')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="start" class="block font-medium text-sm text-gray-700">Start Date</label>
<input type="date" name="start" id="start" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('start', '') }}" />
#error('start')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
<div class="bg-white sm:p-6">
<label for="end" class="block font-medium text-sm text-gray-700">End Date</label>
<input type="date" name="end" id="end" class="form-input rounded-md shadow-sm mt-1 block w-full"
value="{{ old('end', '') }}" />
#error('end')
<p class="text-sm text-red-600">{{ $message }}</p>
#enderror
</div>
</div>
<div class="modal-footer">
<button class="btn" data-dismiss="modal" aria-hidden="true">Cancel</button>
<button type="submit" class="btn btn-primary" data-bs-toggle="modal" data-bs-target="#EditEventModal" id="updateBtn">Save</button>
</div>
</form>
</div>
</div>
</div>
#push('scripts')
<script src='https://cdn.jsdelivr.net/npm/moment#2.27.0/min/moment.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/fullcalendar-scheduler#5.11.3/main.min.js'></script>
<script src='https://cdn.jsdelivr.net/npm/#fullcalendar/moment#5.11.3/main.global.min.js'></script>
<script>
create_UUID = () => {
let dt = new Date().getTime();
const uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
let r = (dt + Math.random() * 16) % 16 | 0;
dt = Math.floor(dt / 16);
return (c == 'x' ? r :(r&0x3|0x8)).toString(16);
});
return uuid;
}
document.addEventListener('livewire:load', function () {
const Calendar = FullCalendar.Calendar;
const calendarEl = document.getElementById('calendar');
const Draggable = FullCalendar.Draggable;
new Draggable(document.getElementById('events'), {
itemSelector: '.dropEvent'
});
const calendar = new Calendar(calendarEl, {
headerToolbar: {
left: 'promptResource prev,next today',
center: 'title',
right: 'resourceMonth,dayGridMonth,timeGridWeek,timeGridDay,listMonth'
},
views: {
resourceMonth: {
type: 'resourceTimelineMonth',
buttonText: 'personnel'
}
},
customButtons: {
promptResource: {
text: "+ personnel",
click: function() {
var title = prompt("Name");
if (title) {
calendar.addResource({
title: title
});
fetch("add_resources.php", {
method: "POST",
headers: {
Accept: "application/json"
},
body: encodeFormData({ title: title })
})
.then(response => console.log(response))
.catch(error => console.log(error));
}
}
}
},
initialView: 'resourceTimelineMonth',
locale: '{{ config('app.locale') }}',
events: JSON.parse(#this.events),
resourceAreaHeaderContent: 'Personnel',
resources: JSON.parse(#this.resources),
editable: true,
eventResize: info => #this.eventChange(info.event),
eventDrop: info => #this.eventChange(info.event),
eventReceive: info => {
const id = create_UUID();
info.event.setProp('id', id);
#this.eventAdd(info.event);
},
formatDate(date) {
return moment.utc(date).format("YYYY-MM-DD HH:mm:ss")
},
selectable: true,
select: function(selectionInfo) {
$('#AddEventModal').find('#start').val(selectionInfo.start);
$('#AddEventModal').find('#end').val(selectionInfo.end);
$('#AddEventModal').modal('show');
$('#saveBtn').click(function() {
var title = $('#title').val();
var start = moment(start).format("YYYY-MM-DD HH:mm:ss");
var end = moment(end).format("YYYY-MM-DD HH:mm:ss");
$.ajax({
url:"{{ route('event.store') }}",
type:"POST",
dataType:'json',
data:{ title, acronym, city, venue, value, start, end, color },
success:function(response)
{
$('#AddEventModal').modal('hide')
$('#calendar').fullCalendar('renderEvent', {
'title': response.title,
'acronym': response.acronym,
'city': response.city,
'venue': response.venue,
'value': response.value,
'start' : response.start,
'end' : response.end,
'color' : response.color
});
},
error:function(error)
{
if(error.responseJSON.errors) {
$('#titleError').html(error.responseJSON.errors.title);
}
},
});
});
},
eventClick: function(info) {
$('#EditEventModal').modal('show');
$('#EditEventModal').find('#id').val(info.event.id);
$('#EditEventModal').find('#title').val(info.event.title);
$('#EditEventModal').find('#acronym').val(info.event.extendedProps.acronym);
$('#EditEventModal').find('#city').val(info.event.extendedProps.city);
$('#EditEventModal').find('#venue').val(info.event.extendedProps.venue);
$('#EditEventModal').find('#value').val(info.event.extendedProps.value);
$('#EditEventModal').find('#start').val(info.event.start);
$('#EditEventModal').find('#end').val(info.event.end);
$('#EditEventModal').modal('show');
$.ajax({
url:"{{ route('event.update', '') }}" +'/'+ id,
type:"PATCH",
dataType:'json',
data:{ start, end },
success:function(response)
{
swal("Good job!", "Event Updated!", "success");
},
error:function(error)
{
console.log(error)
},
});
},
});
calendar.render();
$("#AddEventModal").on("hidden.bs.modal", function () {
$('#saveBtn').unbind();
});
$("#EditEventModal").on("hidden.bs.modal", function () {
$('#updateBtn').unbind();
});
$('.fc-event').css('font-size', '13px');
$('.fc-event').css('width', '20px');
$('.fc-event').css('border-radius', '50%');
});
</script>
<link href='https://cdn.jsdelivr.net/npm/fullcalendar-scheduler#5.11.3/main.min.css' rel='stylesheet' />
#endpush
Here's the applicable routes:
Route::get('calendar/index', [CalendarController::class, 'index'])->name('calendar.index');
Route::post('calendar', [EventController::class, 'store'])->name('event.store');
Route::patch('calendar/update/{id}', [EventController::class, 'update'])->name('event.update');
Route::delete('calendar/destroy/{id}', [EventController::class, 'destroy'])->name('event.destroy');
And here's the Controller:
<?php
namespace App\Http\Controllers;
use App\Http\Requests\StoreEventRequest;
use App\Http\Requests\UpdateEventRequest;
use App\Models\Event;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
use Symfony\Component\HttpFoundation\Response;
class EventsController extends Controller
{
public function index()
{
abort_if(Gate::denies('event_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$events = Event::all();
return view('events.index', compact('events'));
}
public function create()
{
abort_if(Gate::denies('event_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('events.create');
}
public function store(Request $request)
{
$request->validate([
'title' => 'required|string'
]);
$event = Event::create([
'title' => $request->title,
'acronym' => $request->acronym,
'city' => $request->city,
'venue' => $request->venue,
'value' => $request->value,
'start' => $request->start,
'end' => $request->end,
]);
$color = null;
if($event->title == 'Test') {
$color = '#924ACE';
}
return redirect('/dashboard')-> with('success', 'Event Added'); response()->json([
'id' => $event->id,
'title' => $event->title,
'acronym' => $request->acronym,
'city' => $request->city,
'venue' => $request->venue,
'value' => $request->value,
'start' => $event->start,
'end' => $event->end,
]);
}
public function show(Event $event)
{
abort_if(Gate::denies('event_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('events.show', compact('event'));
}
public function edit(Event $event)
{
abort_if(Gate::denies('event_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
return view('events.edit', compact('event'));
}
public function update(Request $request ,$id)
{
$event = Event::find($id);
if(! $event) {
return response()->json([
'error' => 'Unable to locate the event'
], 404);
}
$event->update([
'start' => $request->start,
'end' => $request->end,
]);
return response()->json('Event updated');
}
public function destroy(Event $event)
{
abort_if(Gate::denies('event_access'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$event->delete();
return redirect()->route('events.index');
}
}
EDIT--
Here's the Livewire Calendar component:
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Event;
use App\Models\Resource;
use Illuminate\Support\Arr;
class Calendar extends Component
{
public $events, $resources, $title, $acronym, $city, $venue, $value ;
protected function rules()
{
return [
'title' => 'required|string|min:6',
'acronym' => 'required|string',
];
}
public function eventChange ( $event )
{
$e=Event::find($event['id']) ;
$e->start=$event['start'] ;
if(Arr::exists($event,'end')) {
$e->end=$event['end'];
}
$e->save();
}
public function saveEvent()
{
$validatedData = $this->validate();
Event::create($validatedData);
session()->flash('message','Event Added Successfully');
$this->resetInput();
$this->dispatchBrowserEvent('close-modal');
}
public function render()
{
$this->events=json_encode(Event::all());
$this->resources=json_encode(Resource::all());
return view('livewire.calendar');
}
public function eventAdd ( $event )
{
Event::create ( $event );
}
public function eventRemove ( $id )
{
Event::destroy ( $id );
}
public function resourceAdd ( $resources )
{
Resource::create ( $resources );
}
public function resourceRemove ( $id )
{
Resource::destroy ( $id );
}
}

Display row count from database on a dropdown

I'm working on a Review module in laravel that can sort from All Ratings, Like, and Dislike. However, I'd also like to display the count of All Reviews, likes, and dislikes. Below is my code for the dropdown as well as the model.
Review Dropdown
#props(['routeName', 'username'])
<div class="flex items-center">
<span class="text-sm text-gray-700 uppercase m-1">{{ __('Review:') }}</span>
<div class="relative" x-data="{ open: false }" #click.outside="open = false" #close.stop="open = false">
<div #click="open = ! open">
<button class="flex items-center text-sm font-medium text-gray-500 hover:text-gray-700 hover:border-gray-300 focus:outline-none focus:text-gray-700 focus:border-gray-300 transition duration-150 ease-in-out">
<div>{{ App\Models\Review::RATING[request()->rating] ?? __('All') }}</div>
<div class="ml-1">
<svg class="fill-current h-4 w-4" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 20 20"><path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd" /></svg>
</div>
</button>
</div>
<div x-show="open" class="absolute z-50 mt-2 w-20 rounded-md shadow-lg" style="display: none;" #click="open = false"> {{-- origin-top-right right-0 --}}
<div class="rounded-md ring-1 ring-black ring-opacity-5 py-1 bg-white overflow-y-auto py-1 h-30">
<x-dropdown-link href="{{ route($routeName, [$username]) }}?{{ http_build_query(request()->except('rating', 'page')) }}">
{{ __('All') }}
</x-dropdown-link>
#foreach(App\Models\Review::RATING as $value => $label)
<x-dropdown-link href="{{ route($routeName, [$username]) }}?rating={{ $value }}&{{ http_build_query(request()->except('rating', 'page')) }}">
{{ __($label) }}
</x-dropdown-link>
#endforeach
</div>
</div>
</div>
</div>
ReviewModel
class Review extends Model
{
use HasFactory;
protected $table = 'reviews';
protected $fillable = [
'customer_username',
'customer_id',
'business_id',
'rating',
'feedback'
];
const RATING = [
'1' => 'Dislike',
'2' => 'Like'
];
public function scopeFilter($query, $rating){
$query->when($rating ?? false, function ($query, $rating) {
$query->where(function ($query) use ($rating) {
$query->where('rating', $rating);
});
});
}
}
This is what I intend it to look like:
I did try adding ::count() and ->count() on App\Models\Review::RATING after the foreach in the dropdown but it broke the application.

Livewire component vanish after emitting event

I made chat app using livewire, and i want to emit an event where in that event emitting antohter event to another component, but when i emit the event the component it self vanish from view, and i dont know why here is my code
<div class="flex flex-row py-2 px-2 items-center border-b-2 cursor-pointer hover:bg-gray-100" wire:click="$emit('chatUserSelected',{{$conversation}})">
and the event in chatlist component
protected $listeners = ['chatUserSelected'];
public $conversations;
public $selectedConversation;
public function chatUserSelected(Conversation $conversation)
{
$this->selectedConversation = $conversation;
$receiverInstance = KontakModel::find($conversation->kontak_id);
$this->emitTo('chat.chat-box','loadConversation',$this->selectedConversation,$receiverInstance);
$this->emitTo('chat.send-message','updateSendMessage',$this->selectedConversation,$receiverInstance);
}
public function mount()
{
$this->auth_id = auth()->id();
$this->conversations = Conversation::orderBy('last_time_message','DESC')->where('solved_at',NULL)->get();
// dd($this->conversations);
}
public function render()
{
return view('livewire.chat.chat-list', );
}
here is my view before emitting event
and after emitting event
the chatlist somehow disappear
for additional this is code for my main view
<div class="flex flex-row justify-between bg-white h-screen" x-data="chatApp">
#livewire('chat.chat-list')
#livewire('admin.side-bar')
<!-- message -->
#livewire('chat.chat-box')
<!-- end message -->
</div>
chat.chat-list.blade.php
<div class="overflow-y-auto">
#forelse ($conversations as $conversation)
<div class="flex flex-row py-2 px-2 items-center border-b-2 cursor-pointer hover:bg-gray-100" wire:key="{{$conversation->id}}" wire:click="$emit('chatUserSelected',{{$conversation}})">
<div class="w-1/4">
<img
src="https://source.unsplash.com/otT2199XwI8/600x600"
class="object-cover h-12 w-12 rounded-full"
alt=""
/>
</div>
<div class="w-full">
<div class="text-lg font-semibold">{{ $conversation->kontak->name }}</div>
<span class="text-gray-500">{{$conversation->messages->sortBy('created_at')->last()->body}}</span>
</div>
<div class="w-2/12">
#php
$unread = $conversation->messages->where('status', NULL)->where('category','receive')->count()
#endphp
#if ($unread > 0)
<div class="text-sm text-center font-light rounded-full bg-red-600 text-white min-w-5 h-5">{{$unread}}</div>
#endif
<span class="text-xs">{{$conversation->messages->sortBy('created_at')->last()->created_at->shortAbsoluteDiffForHumans()}}</span>
</div>
</div>
#empty
<div class="flex flex-row py-2 px-2 items-center border-b-2 text-2xl text-center">
<div class="text-center m-auto">
No Conversation
</div>
</div>
#endforelse
</div>

How to speed up requests in livewire?

I’ve made a very simple profile card with two views once is showing me the profile id,name and email and the second view just show the input fields for this three attributes.
This is working but it is “very” slow. When i’m hitting the button Edit on the show view, it takes more than 650ms(in best scenario, sometimes it takes more than 1.2sec) to load the edit view and vice versa.
How can I make this a little bit faster ?
Profile Component:
namespace App\Http\Livewire\User;
use App\User;
use Illuminate\Validation\Rule;
use Livewire\Component;
class Profile extends Component
{
public $user, $user_id, $name, $email;
public $updateMode = false;
public function mount(User $user)
{
$this->user = $user;
$this->user_id = $user->id;
$this->name = $user->name;
$this->email = $user->email;
}
public function render()
{
return view('livewire.user.profile.resource');
}
public function edit()
{
$this->updateMode = true;
}
public function cancel()
{
$this->updateMode = false;
}
public function submit()
{
$attributes = $this->validate([
'name' => 'required|min:6',
'email' => ['required', 'email', Rule::unique('users')->ignore($this->user->id)],
]);
$this->user->update($attributes);
$this->updateMode = false;
}
}
And this are the views:
resource.blade.php:
<div class="p-3">
#includeWhen(!$updateMode,'livewire.user.profile.show')
#includeWhen($updateMode,'livewire.user.profile.edit')
</div>
show.blade.php:
<div>
<div class="flex items-center py-2">
<div class="w-1/4">
<span class="text-gray-800">Id:</span>
</div>
<div class="w-3/4" >
<span class="text-gray-700 font-semibold">{{ $user_id }}</span>
</div>
</div>
<div class="flex items-center py-2">
<div class="w-1/4">
<span class="text-gray-800">Name:</span>
</div>
<div class="w-3/4" >
<span class="text-gray-700 font-semibold">{{ $name }}</span>
</div>
</div>
<div class="flex items-center py-2">
<div class="w-1/4">
<span class="text-gray-800">Email:</span>
</div>
<div class="w-3/4" >
<span class="text-gray-700 font-semibold">{{ $email }}</span>
</div>
</div>
<!-- Editing Buttons -->
<div class="pt-3">
<button type="button" wire:click.prevent="edit" class="py-1 px-2 rounded bg-blue-500 text-white font-semibold">Edit</button>
</div>
</div>
edit.blade.php:
<form wire:submit.prevent="submit">
<div class="flex items-center py-2">
<div class="w-1/4">
<span class="text-gray-800">Id:</span>
</div>
<div class="w-3/4" >
<span class="text-gray-700 font-semibold">{{ $user_id }}</span>
</div>
</div>
<div class="flex items-center py-2">
<div class="w-1/4">
<span class="text-gray-800">Name:</span>
</div>
<div class="w-3/4" >
<input type="text" class="w-1/2 border appearance-none py-1 px-2 rounded shadow focus:outline-none" wire:model="name">
</div>
</div>
<div class="flex items-center py-2">
<div class="w-1/4">
<span class="text-gray-800">Email:</span>
</div>
<div class="w-3/4" >
<input type="text" class="w-1/2 border appearance-none py-1 px-2 rounded shadow focus:outline-none" wire:model="email">
</div>
</div>
<!-- Editing Buttons -->
<div class="pt-3">
<button type="submit" class="py-1 px-2 rounded bg-blue-500 text-white font-semibold" >Save</button>
Cancel
</div>
</form>
I ran into the same issue, with the same implementation approach. I also noticed that it was a bit slow when Livewire would change the state to show/hide the form, so what I did was use Alpine.js for determining whether to show the form or not.
<div x-data="{ mode: 'view' }">
<div x-show="mode === 'edit'">
<div>
<!-- display form here -->
</div>
<button wire:click="update">
Save
</button>
<button #click.prevent="mode = 'view'">
Cancel
</button>
</div>
<div x-show="mode !== 'edit'">
<div>
<!-- profile displayed here -->
</div>
<button #click.prevent="mode = 'edit'">
Edit
</button>
</div>
</div>
Doing it this way resolved the issue with displaying the form, which feels really snappy and quick. I have run into a different issue since that I’m not sure how to address.
If I begin to type in the form to update the name, and quickly hit the save button before the requests to update the component properties complete, then what ever the properties were at the time that I hit the save button are what gets saved to the database, creating a race condition.
I’m still relatively new to the Livewire paradigm so I don’t have a good answer for this yet.

limit () and take () not working properly

im trying to take 3 most viewed post but its just getting only two I don't know why I have tried limit () method it's not showing anything what am I doing wrong here ,
<?php
namespace App\Http\Livewire;
use App\Models\Movie;
use Livewire\Component;
class MovieBox extends Component
{
public function render()
{
return view('livewire.movie-box',[
'movies' => Movie::withCount('read_count')->orderBy('reads', 'desc')->take(3)->get(),
]);
}
}
movie box
<div>
<div class="relative grid grid-cols-3 gap-2 mt-3 user_story md:grid-cols-5">
#foreach ( $movies as $movie )
<a href="#create-post" uk-toggle="target: body ; cls: story-">
<div class="single_story">
<img src="assets/images/avatars/avatar-lg-1.jpg" alt="">
<div class="story-avatar"> <img src="assets/images/avatars/avatar-1.jpg" alt=""></div>
<div class="story-content">
<h4> {{ $movie->title }}</h4>
</div>
</div>
</a>
#endforeach
<span
class="absolute z-10 items-center justify-center hidden p-2 -mr-4 text-xl bg-white rounded-full shadow-md lg:flex w-9 uk-position-center-right"
uk-toggle="target: body ; cls: story-">
<i class="icon-feather-chevron-right"></i></span>
</div>
Change your render method like this.
public function render()
{
return view('livewire.movie-box',[
'movies' => Movie::withCount('read_count')->orderBy('reads', 'desc')->limit(3)->get(),
]);
}

Resources