Why doesn't my Livewire component refresh after event is sent? - php

I have a "Route (Model)" which has many "PickupRequest".
I made a component that displays all components as two lines of text. However, if it's the "currentRequest" (we go through each one one by one), I display another Livewire component.
In my modal, I want to sent the event to "RequestsList" in order to go to the next request and refresh the list to display the right request. The update is made in the DB, but the content of the page doesn't change.
Here is my code:
List:
<?php
namespace App\Http\Livewire\Routes;
use App\Models\PickupRequest;
use App\Models\Route;
use Livewire\Component;
class RequestsList extends Component
{
public Route $route;
public $requests;
public PickupRequest $currentRequest;
protected $listeners = ['nextRequest' => 'nextRequest'];
public function mount() {
$this->requests = $this->route->requestsWithDone;
}
public function booted() {
$this->currentRequest = $this->route->requests()->first();
}
public function nextRequest() {
$this->currentRequest = $this->route->requests()->first();
}
public function render()
{
return view('livewire.routes.requests-list');
}
}
====
<div>
#livewire('routes.in-progress', ['request' => $currentRequest])
#foreach($requests as $request)
#if($request->id != $currentRequest->id)
<div class="overflow-hidden bg-white shadow sm:rounded-lg cursor-pointer mb-4" wire:key="r_{{ $request->id }}">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900">{{ $request->user->short_address }}
<p class="tw-badge {{ $request->status_color }}">{{ $request->status_text }}</p>
</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500">{{ $request->user->special_instructions }}</p>
</div>
</div>
#endif
#endforeach
</div>
InProgress:
<?php
namespace App\Http\Livewire\Routes;
use App\Models\PickupRequest;
use App\Models\Route;
use Livewire\Component;
class InProgress extends Component
{
public PickupRequest $request;
public function render()
{
return view('livewire.routes.in-progress');
}
}
===
<div class="overflow-hidden bg-white shadow sm:rounded-lg mb-4" wire:key="ip_{{ $request->id }}">
<div class="px-4 py-5 sm:px-6">
<h3 class="text-lg font-medium leading-6 text-gray-900">{{ $request->user->short_address }}</h3>
<p class="mt-1 max-w-2xl text-sm text-gray-500">{{ $request->user->special_instructions }}</p>
</div>
<div class="border-t border-gray-200 px-4 py-5 sm:px-6">
<dl class="grid grid-cols-1 gap-x-4 gap-y-8 sm:grid-cols-2">
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500">{{ __('routes.pickup.full_address') }}</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $request->user->full_address }}</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500">{{ __('routes.pickup.special_instructions') }}</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $request->user->special_instructions }}</dd>
</div>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500">{{ __('routes.pickup.phone_number') }}</dt>
<dd class="mt-1 text-sm text-gray-900">{{ $request->user->phone }}</dd>
</div>
<div class="sm:col-span-2">
<dt class="text-sm font-medium text-gray-500">{{ __('routes.pickup.bags') }}</dt>
</div>
<div class="flex flex-row space-x-2 justify-end sm:col-span-2 flex-wrap">
<x-button class="red-button hover:red-button mt-1"
wire:click="$emit('openModal', 'routes.modal.couldnt-pickup', {{ json_encode(['pickup_id' => $request->id]) }})">
{{ __('routes.pickup.cant_pickup') }}
</x-button>
<x-button class="mt-1">{{ __('routes.pickup.add_bag') }}</x-button>
<x-button class="green-button mt-1">{{ __('routes.pickup.end') }}</x-button>
</div>
</dl>
</div>
</div>
Modal (only PHP, the blade is irrelevant imo):
<?php
namespace App\Http\Livewire\Routes\Modal;
use App\Models\PickupRequest;
use Illuminate\Support\Facades\Gate;
use LivewireUI\Modal\ModalComponent;
class CouldntPickup extends ModalComponent
{
public PickupRequest $pickup;
public function mount($pickup_id)
{
$pickup = PickupRequest::findOrFail($pickup_id);
Gate::authorize('update', $pickup);
$this->pickup = $pickup;
}
public function update()
{
Gate::authorize('update', $this->pickup);
if($this->pickup->is_active) {
$this->pickup->couldnt_pickup_at = now();
$this->pickup->save();
}
$this->emit('nextRequest');
$this->closeModal();
}
public function render()
{
return view('livewire.routes.modal.couldnt-pickup');
}
}

If the current livewire component is not directly the children of the recipient of the Emit event you are sending then you should use
$this->emitUp('nextRequest');
To refresh the whole component after you have made the request without reloading the page then you should use the magic function $refresh, the details can be found here, https://laravel-livewire.com/docs/2.x/actions#magic-actions
protected $listeners = ['reloadContent' => '$refresh'];
$this->emit('reloadContent');

The key is supposed to be on the top elements in the parent Livewire component. The key shouldn't be set in the component file in InProgress.

Related

livewire action not happening when link is clicked

So I have popup which contains a form that shows a table with editable cells using livewire and each row has a delete button, above this table is a button to add a new empty row to the table. Editing in the cells is working (click the cell and it changes to the inline edit input) but clicking the delete link does nothing and neither does the add link.
So for this process I have the following in the client index file which loads the popup modal when the button to edit the client is clicked.
For this question I am looking at why the add isn't working but as for the delete that would be a bonus!
<script>
$(document).ready(function() {
$("#clients tbody").on("click", ".actions", function () {
var data = table.row( $(this).parents('tr') ).data();
// now call ajax on this url
call_ajax( "/client/" + data[0] + "/edit" );
loader.style.display = "block";
modal.style.display = "block";
});
});
function call_ajax( url ) {
// ToDo make an actual ajax call to get the form data
$.get( url )
.done(
function( data ) {
$("#content-region").html( data );
}
)
.fail(
function() {
$("#content-region").html( "<p>error</p>" );
}
);
}
</script>
So using this when a client has its action section clicked then a call to client/{x}/edit is called which is calls my edit.blade.php file:
#extends('layouts.popup')
#section('header')
<i class="fa fa-fw fa-pencil-square-o fa-lg text-success"></i> Edit Client
#stop
#section('content')
<div class="client-editor">
<form class="admin-link" method="post" action="client/save">
#csrf
<input type="hidden" name="id" value="{{ old( 'id', $client->id ) }}">
<div class="max-w-10xl mx-auto py-10 sm:px-6 lg:px-8">
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1 flex justify-between">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium text-gray-900">Client Edit</h3>
<p class="mt-1 text-sm text-gray-600">
Update the Client title, you can add and remove contacts below.
</p>
</div>
<div class="px-4 sm:px-0">
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<div class="px-4 py-5 bg-white sm:p-6 shadow sm:rounded-tl-md sm:rounded-tr-md">
<!-- Eclipse Account Handler -->
<div class="col-span-6 sm:col-span-4">
<label class="block font-medium text-sm text-gray-700" for="client_id">
Client Title
</label>
<input
class="border-gray-300 focus:border-indigo-300 focus:ring focus:ring-indigo-200 focus:ring-opacity-50 rounded-md shadow-sm mt-1 block w-full"
id="title"
name="title"
type="text"
value="{{ $client->title }}"
>
</div>
<br>
<div class="col-span-6 sm:col-span-4">
<x-toggle
left="No"
right="Yes"
name="is_enabled"
label="Is this client active?"
colourleft="#805050"
colourright="#508050"
default="{{ $client->is_enabled }}"
/>
</div>
</div>
<div class="hidden sm:block">
<div class="py-8">
<div class="border-t border-gray-200"></div>
</div>
</div>
</div>
</div>
</div>
<!-- client contacts -->
<div class="max-w-10xl mx-auto py-10 sm:px-6 lg:px-8">
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1 flex justify-between">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium text-gray-900">Client Contacts</h3>
<p class="mt-1 text-sm text-gray-600">
Enter details for client contacts assigned to this client.
</p>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<div class="px-4 py-5 bg-white sm:p-6 shadow sm:rounded-tl-md sm:rounded-tr-md">
#livewire("contacts-table", [ 'client' => $client ])
</div>
<div
class="flex items-center justify-end px-4 py-3 bg-gray-50 text-right sm:px-6 shadow sm:rounded-bl-md sm:rounded-br-md">
<button
type="submit"
class="inline-flex items-center px-4 py-2 bg-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring focus:ring-gray-300 disabled:opacity-25 transition"
>
Save
</button>
</div>
<div class="hidden sm:block">
<div class="py-8">
<div class="border-t border-gray-200"></div>
</div>
</div>
</div>
</div>
</div>
</form>
</div>
#stop
and from in this a call of #livewire("contacts-table", [ 'client' => $client ]) and this are it's parts.
ContactsTable.php
<?php
namespace App\Http\Livewire;
use App\Models\Client;
use App\Models\ClientContact;
use Livewire\Component;
class ContactsTable extends Component
{
protected $listeners =['refresh' => '$refresh'];
public Client $client;
public $clientContacts;
public function mount( Client $client )
{
$this->clientContacts = ClientContact::where( 'client_id', $client->id )->get();
}
public function render()
{
return view('livewire.contacts-table');
}
public function addNewContact()
{
die('Test that we got here!'); // I actually have a breakpoint here.
}
}
and contacts-table.blade.php:
<div class="col-span-6 sm:col-span-4">
<a
class="inline-flex items-center px-4 py-2 bg-gray-800 dark:bg-gray-100 dark:text-gray-800 border border-transparent rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700 active:bg-gray-900 focus:outline-none focus:border-gray-900 focus:ring focus:ring-gray-300 disabled:opacity-25 transition"
wire:click="addNewContact"
>
{{ __('Add') }}
</a>
<table id="contacts" class="table table-striped table-bordered table-hover">
<thead>
<td>Name</td>
<td>Email</td>
<td>Phone</td>
<td>Action</td>
</thead>
<tbody>
#foreach( $clientContacts as $contact )
<tr id="{{ $contact->id }}">
<td>
#livewire( 'inline-edit', ['item' => $contact, 'type' => 'title', 'number' => $client->id] )
</td>
<td>
#livewire( 'inline-edit', ['item' => $contact, 'type' => 'email', 'number' => $client->id] )
</td>
<td>
#livewire( 'inline-edit', ['item' => $contact, 'type' => 'phone_number', 'number' => $client->id] )
</td>
<td class="width-8">
<a
class="cursor-pointer"
wire:click="$emit( 'openModal', 'delete-contact',{{ json_encode(['contact_id' => $contact->id]) }} )"
>
<i class="fas fa-trash"></i>
</a>
</td>
</tr>
#endforeach
</tbody>
</table>
<p class="mt-1 text-sm text-gray-600">
Edit the cells above, click the bin to delete or the + to add a new row to populate with a new contact.
</p>
</div>
for completeness here is the popup layout blade file:
<!-- Page Heading-->
<header class="bg-white shadow">
<div class="max-w-7xl mx-auto py-6 px-4 sm:px-6 lg:px-8">
<h2 class="font-semibold text-xl text-gray-800 leading-tight">
#yield('header')
</h2>
</div>
</header>
<!-- Page Content -->
<main>
#if (Session::has('message'))
<!-- will be used to show any messages -->
<div class="alert alert-info">{{ Session::get('message') }}</div>
#endif
<div class="py-12">
<div class="bg-white overflow-hidden shadow-xl sm:rounded-lg">
#yield('content')
</div>
</div>
</main>
<!-- End Popup -->
Just to reiterate, the popup form is loading and the content in it is rendered correctly. The top part of the form works so the client is updated.
The inline edit livewire is working (well kind of as I've yet to implement the actual save of it's data but that isn't my issue.
The add button does nothing and nothing is shown in my dev toolbar (no network activity and nothing in the console tab) this is also the case with the delete buttons (which i have working elsewhere in the app - it should show a confirm box and if yes it then removes the contact.
thanks
*** EDIT ***
As an afterthought I have tried this with the client table commented ( the entire table in contacts-table.blade.php) so it just has the add link but it still doesn't work.
*** MORE INFO ***
I have tried removing from the popup and it works this way. Not what I wanted but It does work this way. Why would it not work in a popup?

ErrorException Trying to get property 'title' of non-object (View: C:\DK\Practice\Laravel\example-app\resources\views\product.blade.php)

I am getting below shown error in Laravel website. The goal over here is to display the product. I have also shared the image of the error on this issue log. Kindly check and let me know where the issue is as I am not able to figure out.
I am running the laravel project locally. Any suggestion or help from the Laravel community is welcomed. Please help so that I can proceed further.
ErrorException
Trying to get property 'title' of non-object (View: C:\DK\Practice\Laravel\example-app\resources\views\product.blade.php)
Illuminate\Foundation\Bootstrap\HandleExceptions::handleError
C:\DK\Practice\Laravel\example-app\resources\views/product.blade.php:9
<x-base-layout>
<div class="flex m-4">
<div class="w-1/2 rounded shadow overflow-hidden">
{{-- <img class="object-cover w-full" src="{{asset($product->image_url)}}"/> --}}
</div>
<div class="w-1/2 rounded bg-white ml-2 p-4 shadow relative">
<div class="font-semibold">{{$product->title}}</div>
<div class="text-sm text-gray-500">{{$product->short_desc}}</div>
<div class="text-xs text-gray-500 mt-2">{{$product->long_desc}}</div>
{{-- Seller info --}}
<div class="mt-4">
<div class="text-xs font-semibold text-gray">Sold by</div>
<div class="text-sm text-gray-500">{{$product->user->name}}</div>
</div>
1 - product.blade.php
<x-base-layout>
<div class="flex m-4">
<div class="w-1/2 rounded shadow overflow-hidden">
{{-- <img class="object-cover w-full" src="{{asset($product->image_url)}}"/> --}}
</div>
<div class="w-1/2 rounded bg-white ml-2 p-4 shadow relative">
<div class="font-semibold">{{$product->title}}</div>
<div class="text-sm text-gray-500">{{$product->short_desc}}</div>
<div class="text-xs text-gray-500 mt-2">{{$product->long_desc}}</div>
{{-- Seller info --}}
<div class="mt-4">
<div class="text-xs font-semibold text-gray">Sold by</div>
<div class="text-sm text-gray-500">{{$product->user->name}}</div>
</div>
<div class="mt-2">
<div class="text-xs font-semibold text-gray">Phone number</div>
#auth
<div class="text-sm text-gray-500">{{$product->user->phone}}</div>
#else
<div class="text-sm text-gray-500">********** Login to view</div>
#endauth
</div>
<div class="mt-2">
<div class="text-xs font-semibold text-gray">Email address</div>
#auth
<div class="text-sm text-gray-500">{{$product->user->email}}</div>
#else
<div class="text-sm text-gray-500">********** Login to view</div>
#endauth
</div>
{{-- Product price --}}
<div class="absolute bottom-0 right-0 m-6 rounded-full px-4 py-2 bg-green-500">
<div class="text-white font-fold text-sm">Rs. {{$product->price}}/-</div>
</div>
</div>
</div>
</x-base-layout>
2 - ProductsController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Product;
use Illuminate\Support\Facades\Auth;
class ProductsController extends Controller
{
//fetch all products
public function index() {
$products=Product::all();
return view('products')->with('products',$products);
}
//Fetch a product by id
public function show($id){
$product=Product::find($id);
return view('product')->with('product',$product);
dd($product);
}
3 - Route - web.php
<?php
use App\Http\Controllers\ProductsController;
use Illuminate\Support\Facades\Route;
/*
|--------------------------------------------------------------------------
| Web Routes
|--------------------------------------------------------------------------
|
| Here is where you can register web routes for your application. These
| routes are loaded by the RouteServiceProvider within a group which
| contains the "web" middleware group. Now create something great!
|
*/
Route::get('/dashboard', function () {
return view('dashboard');
})->middleware(['auth'])->name('dashboard');
Route::get('/',[ProductsController::class,'index']
);
Route::get('/product/{id}',[ProductsController::class,'show']);
Error screenshot:
I think, you have a little prob in your show() method. What happen if the find method return a null? You will exactly get what you are getting, trying to access a property on null object.
Change you code as bellow, and then you'll get a 404 Not found.
//Fetch a product by id
public function show($id){
$product=Product::findOrFail($id);
return view('product')->with('product',$product);
dd($product); // This will never be executed.
}

Passing data from controller to modal

I'm am trying to get data from a database table and passing it to the modal but it is saying the array I am passing in undefined. Here is my Controller:
public function displayLocNotesForModal() {
$notesLoc = Note::all();
return view('/components/callCenter/modalLocNotes', ['notesLoc' => $notesLoc]);
}
Here is my Route:
Route::get('/components/callCenter/modalLocNotes', 'App\Http\Controllers\CallCenter\NoteController#displayLocNotesForModal');
Here is my modal:
<div class="mt-3 text-center sm:mt-0 sm:ml-4 sm:text-left">
<h3 class="text-lg leading-6 font-medium text-gray-900" id="modal-headline">
Location #{{ $title }} Notes
</h3>
<div class="mt-2">
<p class="text-sm leading-5 text-gray-500">
{{-- {{ $slot }} --}}
#foreach($notesLoc as $notes)
#if($notes == $title)
works
#endif
#endforeach
</p>
</div>
</div>
I think it should be like below, assuming the components folder is in your resources/views folder
return view('components.callCenter.modalLocNotes', ['notesLoc' => $notesLoc]);
Also providing a link to docs Laravel nested view directories

Larvel Update and Destroy route not working [duplicate]

This question already has answers here:
How to make a delete request with Laravel
(2 answers)
Closed 2 years ago.
The accept button has the route route('members.update', $member->id)
The deny button has the route route('members.destroy', $member->id)
These are the cards:
#foreach ($members as $member)
<div class="my-1 px-1 w-full md:w-1/2 lg:my-4 lg:px-4 lg:w-1/3">
<article class="bg-white overflow-hidden rounded-lg shadow-lg">
<div class="flex items-center justify-between leading-tight p-2 md:p-4 w-max">
<div class="w-1/2">
<small class="text-gray-600">Full name:</small>
<h1 class="text-lg pr-2"> {{ $member->firstname }} {{ $member->lastname }} </h1>
</div>
<div class="w-1/2">
<small class="text-gray-600">Birthdate:</small>
<h1 class="text-lg">{{ date('d-m-Y', strtotime($member->birthdate)) }}</h1>
</div>
</div>
<div class="flex items-center justify-between leading-tight p-2 md:p-4">
<div class="w-1/2">
<small class="text-gray-600">Student id:</small>
<h1 class="text-lg pr-2">{{ $member->studentid }}</h1>
</div>
<div class="w-1/2">
<small class="text-gray-600">Discord:</small>
<h1 class="text-lg">{{ $member->discordname }}{{ $member->discordtag }}</h1>
</div>
</div>
<footer class="flex items-center leading-tight p-2 md:p-4 justify-start">
<form method="PATCH" action="{{ route('members.update', $member->id) }}">
#method('PATCH')
<button class="bg-green-500 hover:bg-green-700 text-white font-bold py-2 px-4 rounded mr-2">Accept</button>
#csrf
</form>
<form method="DELETE" action="{{ route('members.destroy', $member->id) }}">
#method('DELETE')
<button class="bg-red-500 hover:bg-red-700 text-white font-bold py-2 px-4 rounded">Deny</button>
#csrf
</form>
</footer>
</article>
</div>
#endforeach
And this is my controller:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Member;
use Illuminate\Http\Request;
class MemberController extends Controller {
public function index() {
$members = Member::where(['status' => false])->get();
return view('dashboard')->with(['members' => $members]);
}
public function show($id) {
$members = Member::where(['id' => $id])->get();
return view('dashboard')->with(['members' => $members]);
}
public function store(Request $request) {
$validatedData = $request->validate([
'firstname' => 'required|max:255|alpha|min:2',
'lastname' => 'required|max:255|alpha|min:2',
'studentid' => 'required|integer|alpha_num',
'birthdate' => 'required|date',
'discordname' => 'required|max:255',
'discordtag' => 'required|max:255|size:5'
]);
$member = new Member;
$member->firstname = $request->firstname;
$member->lastname = $request->lastname;
$member->studentid = $request->studentid;
$member->birthdate = $request->birthdate;
$member->discordname = $request->discordname;
$member->discordtag = $request->discordtag;
$member->status = false;
$member->save();
return \redirect()->route('index');
}
public function update($id) {
die;
$member = Member::find($id);
$member->status = 1;
$member->save();
return \redirect()->route('dashboard');
}
/**
* TODO - SEND EMAIL ON DELETE
*
* #return void
*/
public function destroy($id) {
DB::delete('delete members where id = ?', [$id]);
}
public function accepted($id) {
update($id);
}
}
My routes:
When i click the accept or deny button it sends me to this link: http://hit.localhost.nl/members/3?_method=PATCH&_token=0g5odDLEKCicceDOf4EuPMGIB1X95cwWHGMxMqcR
And runs the show() function instead of the update or destroy functions. What am i doing wrong here?
method="PATCH" and method="DELETE" don't exist, just get, post and dialog. Change both of those to method="post".

Laravel : Invalid parameter number: parameter was not defined

I had this method working before with mysql database but as i have switched my environment to postgresql I got this error.
Facade\Ignition\Exceptions\ViewException
SQLSTATE[HY093]: Invalid parameter number: parameter was not defined
(SQL: select "teachers".*, "student_likes"."student_id" as "pivot_student_id",
"student_likes"."liked_teacher_id" as "pivot_liked_teacher_id"
from "teachers" inner join "student_likes" on "teachers"."id" = "student_likes"."liked_teacher_id"
where "student_likes"."student_id" = 1 and "liked_teacher_id" in (1))
(View: /home/leno/sites/schooly/resources/views/student/likes/index.blade.php)
basically I am trying to perform a match system if both users have liked each other and only display the users if they are a match.
public function matchedTeachers()
{
return $this->likedTeachers()->whereIn('liked_teacher_id', $this->likedStudents->keyBy('liked_teacher_id'));
}
public function likedTeachers()
{
return $this->belongsToMany(Teacher::class, 'student_likes', 'student_id', 'liked_teacher_id');
}
public function likedStudents()
{
return $this->belongsToMany(Student::class, 'teacher_likes', 'teacher_id', 'liked_student_id');
}
#foreach (current_student()->matchedTeachers as $teacher)
<div class="flex flex-col border hover:shadow-lg border-darkindigo-100 rounded-lg">
<div class="flex-1 px-3">
<img src="{{ $teacher->avatar }}" class="block lg:w-20 lg:h-20 rounded-full shadow-xl mx-auto -mt-0 h-20 w-20 bg-cover bg-center object-cover mb-4 mt-4">
<img src="{{ $teacher->teacher_avatar }}" class="block lg:w-10 lg:h-10 rounded-full border-2 border-teal-400 shadow-xl mx-auto -mt-12 ml-32 h-20 w-20 bg-cover bg-center object-cover mb-4 border:z-10">
<div class="text-sm lg:text-lg font-lato font-bold text-gray-800 capitalize text-center leading-8">{{ $teacher->name }}</div>
<div class="text-sm lg:text-sm font-lato font-bold text-gray-700 capitalize text-center">{{ $teacher->language }}</div>
</div>
</div>
#endforeach

Categories