I am getting an error which is shown in the image below when i am trying to update information [closed] - laravel

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 4 days ago.
Improve this question
I have this error please help:
Too few arguments to function App\Http\Requests\ReservationStoreRequest::Illuminate\Foundation\Providers{closure}(), 0 passed in E:\XAMPP\htdocs\resto_app\vendor\laravel\framework\src\Illuminate\Macroable\Traits\Macroable.php on line 124 and exactly 1 expected
<?php
namespace App\Http\Controllers\Admin;
use App\Enums\TableStatus;
use App\Http\Controllers\Controller;
use App\Http\Requests\ReservationStoreRequest;
use App\Models\Reservation;
use App\Models\Table;
use Carbon\Carbon;
use Illuminate\Http\Request;
class ReservationController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$reservations = Reservation::all();
return view('admin.reservations.index', compact('reservations'));
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
// dd($tables);
$tables = Table::where('status', TableStatus::Available)->get();
return view('admin.reservations.create', compact('tables'));
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(ReservationStoreRequest $request)
{
$table = Table::findorFail($request->table_id);
if($request->guest_number > $table->guest_number){
return back()->with('warning', 'Please choose the table base on guests.');
}
$request_date = Carbon::parse($request->res_date);
foreach ($table->reservations as $res) {
if ($res->res_date->format('Y-m-d') == $request_date->format('Y-m-d')) {
return back()->with('warning', 'This table base is reserved for this date.');
}
}
Reservation::create($request->validated());
return to_route('admin.reservations.index')->with('success', 'Reservation created successfully');
}
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show($id)
{
//
}
/**
* Show the form for editing the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function edit(Reservation $reservation)
{
$tables = Table::where('status', TableStatus::Available)->get();
return view('admin.reservations.edit', compact('reservation', 'tables'));
}
/**
* Update the specified resource in storage.
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(ReservationStoreRequest $request, Reservation $reservation)
{
$table = Table::findorFail($request->table_id);
if($request->guest_number > $table->guest_number){
return back()->with('warning', 'Please choose the table base on guests.');
}
$request_date = Carbon::parse($request->res_date);
$reservations = $table->reservations()->where('id', '!=', $reservation->id)->get();
foreach ($reservations as $res) {
if ($res->res_date->format('Y-m-d') == $request_date->format('Y-m-d')) {
return back()->with('warning', 'This table base is reserved for this date.');
}
}
$reservation->update($request->validate());
return to_route('admin.reservations.index')->with('success', 'Reservation updated successfully');
}
/**
* Remove the specified resource from storage.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function destroy($id)
{
//
}
}
this is my view
<x-admin-layout>
<x-slot name="header">
<h2 class="font-semibold text-xl text-gray-800 dark:text-gray-200 leading-tight">
{{ __('Dashboard') }}
</h2>
</x-slot>
<div class="py-12">
<div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
<div class="flex m-2 p-2">
<a href = "{{ route('admin.tables.index')}}"
class="px-4 py-2 bg-indigo-500 hover:bg-indigo-700 rounded-lg text-white"
style="background-color:blue;">Tables index</a>
</div>
<div class="m-2 p-2 bg-slate-100 rounded" style="background-color:lightblue;">
<div class="space-y-8 divide-y divide-gray-200 w-1/2 mt-10">
<form method="POST" action="{{ route('admin.reservations.update', $reservation->id)}}">
#csrf
#method('PUT')
<div class="sm:col-span-6">
<label for="first_name" class="block text-sm font-medium text-gray-700">First Name</label>
<div class="mt-1">
<input type="text" id="first_name" name="first_name" value="{{ $reservation->first_name }}"
class="block w-full appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
</div>
#error('first_name')
<div class="text-sm text-red-400">{{ $message }}</div>
#enderror
</div>
<div class="sm:col-span-6">
<label for="last_name" class="block text-sm font-medium text-gray-700">Last Name</label>
<div class="mt-1">
<input type="text" id="last_name" name="last_name" value="{{ $reservation->last_name }}"
class="block w-full appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
</div>
#error('last_name')
<div class="text-sm text-red-400">{{ $message }}</div>
#enderror
</div>
<div class="sm:col-span-6">
<label for="email" class="block text-sm font-medium text-gray-700">Email</label>
<div class="mt-1">
<input type="email" id="email" name="email" value="{{ $reservation->email }}"
class="block w-full appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
</div>
#error('email')
<div class="text-sm text-red-400">{{ $message }}</div>
#enderror
</div>
<div class="sm:col-span-6">
<label for="tel_number" class="block text-sm font-medium text-gray-700">Phone Number</label>
<div class="mt-1">
<input type="text" id="tel_number" name="tel_number" value="{{ $reservation->tel_number }}"
class="block w-full appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
</div>
#error('tel_number')
<div class="text-sm text-red-400">{{ $message }}</div>
#enderror
</div>
<div class="sm:col-span-6">
<label for="res_date" class="block text-sm font-medium text-gray-700">Reservation Date</label>
<div class="mt-1">
<input type="datetime-local" id="res_date" name="res_date"
value="{{ $reservation->res_date->format('Y-m-d\TH:i:s') }}"
class="block w-full appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
</div>
#error('res_date')
<div class="text-sm text-red-400">{{ $message }}</div>
#enderror
</div>
<div class="sm:col-span-6">
<label for="guest_number" class="block text-sm font-medium text-gray-700"> Guest Number
</label>
<div class="mt-1">
<input type="number" id="guest_number" name="guest_number" value="{{ $reservation->guest_number }}"
class="block w-full appearance-none bg-white border border-gray-400 rounded-md py-2 px-3 text-base leading-normal transition duration-150 ease-in-out sm:text-sm sm:leading-5" />
</div>
#error('guest_number')
<div class="text-sm text-red-400">{{ $message }}</div>
#enderror
</div>
<div class="sm:col-span-6 pt-5">
<label for="status" class="block text-sm font-medium text-gray-700">Table</label>
<div class="mt-1">
<select id="table_id" name="table_id" class="form-multiselect block w-full mt-1">
#foreach ($tables as $table)
<option value="{{ $table->id }}"
#selected($table->id == $reservation->table_id)>{{ $table->name }}
({{ $table->guest_number }} Guests)
</option>
#endforeach
</select>
</div>
#error('table_id')
<div class="text-sm text-red-400">{{ $message }}</div>
#enderror
</div>
<div class="mt-6 p-4">
<button type="submit"
class="px-4 py-2 bg-indigo-500 hover:bg-indigo-700 rounded-lg text-white">Update</buttom>
</div>
</form>
</div>
</div>
</div>
</div>
</x-admin-layout>

Your error is that on the update method you used $reservation->update($request->validate()) but it must be $reservation->update($request->validated()) (see validate vs validated)

Related

Laravel livewire dynamic dropdown with lots of relations on a single model

I have a fairly complex issue, I have an animal
model
class Animal extends Model
{
use HasFactory;
protected $fillable = [
"breed_ID",
"name",
"color_ID",
"eyes_color_ID",
"birth_date",
"animal_types_id",
"born_location",
"profile_picture_id",
"gender_ID",
"status",
"image",
"bio",
"lenght",
"weight",
"passport_url",
"chip_number",
"breeder_ID",
];
protected function genders(): BelongsTo
{
return $this->belongsTo(Gender::class);
}
public function borns(): BelongsTo
{
return $this->belongsTo(Born::class);
}
public function eyeColors(): BelongsTo
{
return $this->belongsTo(EyeColor::class);
}
public function colors(): BelongsTo
{
return $this->belongsTo(Color::class);
}
public function breeders(): BelongsTo
{
return $this->belongsTo(Breeder::class);
}
public function weights(): BelongsTo
{
return $this->belongsTo(Weight::class);
}
public function lengths(): BelongsTo
{
return $this->belongsTo(Length::class);
}
public function users(): BelongsTo
{
return $this->belongsTo(User::class);
}
public function animalTypes(): BelongsTo
{
return $this->belongsTo(AnimalType::class);
}
public function images(): HasMany
{
return $this->hasMany(Image::class);
}
}
This animal has a breed, gender, color e.t.c
When a user wants to add a new animal they are presented a form, this form is a full page livewire component.
<main class="add-animal-page">
<section class="relative">
<div class="container px-4 mx-auto">
<div
class="flex flex-col justify-center w-full min-w-0 mb-6 break-words rounded-lg shadow-xl xl:flex-row bg-gray-50">
<form enctype="multipart/form-data" class="flex justify-center" wire:submit.prevent="upload">
<div class="w-full xl:w-4/6">
<div class="flex justify-center px-4 py-5 sm:p-6">
<div class="grid max-w-4xl grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3 lg:col-span-2">
<label for="first_name" class="block text-sm font-medium text-gray-700">Name</label>
<input type="text" name="first_name" id="first_name" autocomplete="given-name"
wire:model.defer="animal.name"
class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div class="col-span-6 sm:col-span-6">
<label for="type" class="block text-sm font-medium text-gray-700">
Type</label>
<select wire:model="animal.breeds_id" name="breed" id="breed"
class="block w-full px-3 py-2 mt-1 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="">Choose a type</option>
#foreach ($types as $type)
<option value={{ $type->id }}>{{ $type->animal_name }}</option>
#endforeach
</select>
</div>
<div class="col-span-6 sm:col-span-6">
<label for="breed" class="block text-sm font-medium text-gray-700">
Breed</label>
<select wire:model="animal.breeds_id" name="breed" id="breed"
class="block w-full px-3 py-2 mt-1 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="">Choose a breed</option>
#foreach ($breeds as $breed)
<option value={{ $breed->id }}>{{ $breed->breed_name }}</option>
#endforeach
</select>
</div>
<div class="col-span-6 sm:col-span-6">
<label for="breed" class="block text-sm font-medium text-gray-700">
Breed</label>
<select wire:model="animal.breeds_id" name="breed" id="breed"
class="block w-full px-3 py-2 mt-1 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="">Choose a breed</option>
#foreach ($breeds as $breed)
<option value={{ $breed->id }}>{{ $breed->breed_name }}</option>
#endforeach
</select>
</div>
<div class="col-span-6 sm:col-span-6">
<label for="gender" class="block text-sm font-medium text-gray-700">
Gender</label>
<select wire:model="animal.genders_id" name="gender" id="gender"
class="block w-full px-3 py-2 mt-1 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="">Choose a gender</option>
#foreach ($genders as $gender)
<option value={{ $gender->id }}>{{ $gender->type }}</option>
#endforeach
</select>
</div>
<div class="col-span-6 sm:col-span-6">
<label for="eye_color" class="block text-sm font-medium text-gray-700">
Eye color</label>
<select wire:model="animal.eye_color_id" name="eye_color" id="eye_color"
class="block w-full px-3 py-2 mt-1 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="">Choose an eye color</option>
#foreach ($eyeColors as $eyeColor)
<option value={{ $eyeColor->id }}>{{ $eyeColor->name }}</option>
#endforeach
</select>
</div>
<div class="col-span-6 sm:col-span-6">
<label for="Breeder" class="block text-sm font-medium text-gray-700">
Breeder</label>
<select wire:model="animal.breeders_id" name="Breeder" id="Breeder"
class="block w-full px-3 py-2 mt-1 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="">Choose a breeder</option>
#foreach ($breeders as $breeder)
<option value={{ $breeder->id }}>{{ $breeder->name }}</option>
#endforeach
</select>
</div>
<div class="col-span-6 sm:col-span-6">
<label for="passport" class="block text-sm font-medium text-gray-700">
Passport URL</label>
<input type="text" wire:model.defer="animal.passport_url" name="passport"
id="passport" autocomplete="text"
class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div class="col-span-6 sm:col-span-6">
<label for="chip_number" class="block text-sm font-medium text-gray-700">
Chip number</label>
<input type="text" wire:model.defer="animal.chip_number" name="chip_number"
id="chip_number" autocomplete="chip_number"
class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</div>
<div class="col-span-6">
<label for="bio" class="block text-sm font-medium text-gray-700">
Bio
</label>
<div class="mt-1">
<textarea wire:model.defer="animal.bio" id="bio" name="bio" rows="3"
class="block w-full mt-1 border-gray-300 rounded-md shadow-sm focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
</textarea>
</div>
</div>
</div>
</div>
<div class="max-w-md mx-auto overflow-hidden rounded-lg md:max-w-xl">
<div class="md:flex">
<div class="w-full p-3 ">
<div
class="relative flex items-center justify-center h-48 bg-gray-100 border-2 border-dotted rounded-lg border-primary-light">
<div class="absolute">
<div class="flex flex-col items-center"><i
class="fa fa-folder-open fa-4x text-primary"></i> <span
class="block font-normal text-gray-400">Upload your image
here</span>
</div>
</div>
<input wire:model.defer="image" type="file"
class="w-full h-full opacity-0 cursor-pointer">
</div>
</div>
</div>
</div>
</div>
<div class="absolute bottom-0 right-0 px-6 py-3 mx-4 my-6 text-right bg-gray-50 sm:px-6">
<button type="submit"
class="inline-flex justify-center px-4 py-2 text-sm font-medium text-white border border-transparent rounded-md shadow-sm bg-primary hover:bg-primary-hover focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500">
Save
</button>
</div>
</form>
</div>
</div>
</section>
</main>
The form is populated via this livewire class.
class AddAnimal extends Component
{
use WithFileUploads;
public User $user;
public Animal $animal;
public Collection $genders;
public Collection $eyeColors;
public Collection $breeds;
public Collection $colors;
public Collection $breeders;
public Collection $types;
public $image;
protected array $rules = [
'animal.name' => 'required|min:2',
'animal.eye_color_id' => 'nullable',
'animal.bio' => 'nullable',
'animal.breeds_id' => 'nullable',
'animal.genders_id' => 'nullable',
'animal.breeders_id' => 'nullable',
'animal.chip_number' => 'nullable',
'animal.passport_url' => 'nullable',
'image' => 'nullable',
];
public function mount(User $user)
{
$this->user = $user;
$this->animal = new Animal();
$this->genders = Gender::all();
$this->eyeColors = EyeColor::all();
$this->breeds = Breed::all();
$this->colors = Color::all();
$this->breeders = Breeder::all();
$this->types = AnimalType::all();
}
public function render()
{
return view('livewire.add-animal')
->layout('components.layouts.dashboard', ['title' => 'Add-animal'])
->with(['user' => $this->user, 'genders' => $this->genders, 'eyeColors' => $this->eyeColors, 'breeds' => $this->breeds, 'colors' => $this->colors, 'breeders' => $this->breeders, 'types' => $this->types]);
}
How can I make it so that my dropdowns become dynamic? e.g if a user selects dog as animal type, in the breed dropdown only relevant dog breeds should be shown, and not cats or horses. I tried using some of the online available tutorials to get me started, but could not figure it out with all the relationships going on in my models.
Since the Breed Model has an animal_type id, we can use Livewire's updated hook to check for changes on the animal type and render only breeds related to the animal type.
so in the livewire component,
class AddAnimal extends Component
{
public User $user;
public Animal $animal;
public Collection $genders;
public Collection $eyeColors;
// public Collection $breeds; we will use a computed property
public Collection $colors;
public Collection $breeders;
public Collection $types;
public $image;
// newly added variable to keep track of animal type changed
public $filters = [
'animal_type_id' => ''
];
protected array $rules = [
'animal.name' => 'required|min:2',
'animal.eye_color_id' => 'nullable',
'animal.bio' => 'nullable',
'animal.breeds_id' => 'nullable',
'animal.genders_id' => 'nullable',
'animal.breeders_id' => 'nullable',
'animal.chip_number' => 'nullable',
'animal.passport_url' => 'nullable',
'image' => 'nullable',
'animal.animal_type_id' => '', // make sure you have the rule can be left empty if its not required
];
public function mount(User $user)
{
$this->user = $user;
$this->animal = new Animal();
$this->genders = Gender::all();
$this->eyeColors = EyeColor::all();
$this->colors = Color::all();
$this->breeders = Breeder::all();
$this->types = AnimalType::all();
}
public function updatedAnimalAnimalTypeId($value)
{
$this->filters['animal_type_id'] = $value;
}
public function getBreedsProperty()
{
return Breed::when($this->filters['animal_type_id'], function($query, $animal_type_id){
return $query->where('animal_type_id', $animal_type_id);
})->get();
}
public function render()
{
return view('livewire.add-animal')
->layout('components.layouts.dashboard', ['title' => 'Add-animal'])
->with(['user' => $this->user, 'genders' => $this->genders, 'eyeColors' => $this->eyeColors, 'breeds' => $this->breeds, 'colors' => $this->colors, 'breeders' => $this->breeders, 'types' => $this->types]);
}
}
Note that I have used computed property to get the breeds.
I also have made use of when clause to avoid the null check.
so in the blade file, we just have to wire:model the animal_type_id.
....
<div class="col-span-6 sm:col-span-6">
<label for="type" class="block text-sm font-medium text-gray-700">
Type</label>
<select wire:model="animal.animal_type_id" name="animal_type_id" id="animal_type_id"
class="block w-full px-3 py-2 mt-1 bg-white border border-gray-300 rounded-md shadow-sm focus:outline-none focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<option value="">Choose a type</option>
#foreach ($types as $type)
<option value={{ $type->id }}>{{ $type->animal_name }}</option>
#endforeach
</select>
</div>
....
Now the breeds will be rendered based on the animal type selected.
I have assumed animal_type_id is the correct column name in Animal model. if its not, please change the column name respectively.

Saved date does not show up in the form

I'm using laravel livewire and I've created a page that you can select a date for when you want the post
to publish. When I create a new post and save the date then it saves fine in the database, but if I try
to edit the post and change the date the date that I saved in the database isn't showing in the form.
Here is my code.
My EditPost.php
<?php
namespace App\Http\Livewire;
use App\Models\Post;
use Livewire\Component;
class EditPost extends Component
{
public $name;
public $publishDate;
public Post $post;
public function mount(Post $post)
{
$this->name = $post->name;
$this->publishDate = $post->publish_date;
}
public function render()
{
return view('livewire.edit-post');
}
}
and this is my edit.blade.php
<div>
<div class="mt-10 sm:mt-0">
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">Edit Post</h3>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<div class="form">
<div class="shadow overflow-hidden sm:rounded-md">
<div class="px-4 py-5 bg-white sm:p-6">
<div class="grid grid-cols-6 gap-6">
<div class="col-span-6 sm:col-span-3">
<label for="name" class="block text-sm font-medium leading-5 text-gray-700">Name</label>
<input id="name" wire:model="name" class="#error('name') border border-red-500 #enderror mt-1 form-input block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5">
#error('name')
<small>
<div class="text-red-500">{{ $message }}</div>
</small>
#enderror
</div>
<div class="col-span-6 sm:col-span-4">
<label for="publish_date" class="block text-sm font-medium leading-5 text-gray-700">Publish Date</label>
<input id="publish_date" wire:model="publishDate" type="date" class="mt-1 form-input block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5">
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<button wire:click="editPost" class="py-2 px-4 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 shadow-sm hover:bg-indigo-500 focus:outline-none focus:shadow-outline-blue active:bg-indigo-600 transition duration-150 ease-in-out">
Save
</button>
</div>
</div>
</div>
</div>
</div>
</div>
</div>

Getting my toggle to show correctly in laravel livewire

I have a pivot table that links my products and categories together. What I'm trying to do is in my edit page for a product I
have a list of all the categories and each category has a toggle button that will enable or disable that category for that product.
The problem I'm having is that all my categories is set to enabled, but I only have one enabled and the rest is supposed to be disabled
I'm using laravel 8 and livewire
Here is my code
namespace App\Http\Livewire\Products;
use App\Models\Product;
use Livewire\Component;
use App\Models\Category;
class Edit extends Component
{
public Product $product;
public bool $enabled;
public $name;
public $description;
public function mount()
{
$pcPivot = $this->product->categories()->where('product_id', $this->product->id)->exists();
if($pcPivot === true)
{
$this->enabled = true;
}else{
$this->enabled = false;
}
$this->name = $this->product->name;
$this->description = $this->product->description;
}
public function render()
{
$categories = Category::all();
return view('livewire.products.edit', [
'categories' => $categories,
]);
}
}
and here is my edit.blade.php
<div>
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">Edit Product</h3>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<form wire:submit.prevent="submit">
<div class="px-4 py-5 bg-white sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="title" class="block text-sm font-medium leading-5 text-gray-700">
Name
</label>
<div class="rounded-md shadow-sm">
<input id="name" wire:model="product.name" class="flex-1 form-input block w-full min-w-0 transition duration-150 ease-in-out sm:text-sm sm:leading-5">
</div>
</div>
</div>
</div>
<div class="px-4 py-5 bg-white sm:p-6">
<div class="grid grid-cols-3 gap-6">
<div class="col-span-3 sm:col-span-2">
<label for="description" class="block text-sm font-medium leading-5 text-gray-700">
Description
</label>
<div class="rounded-md shadow-sm">
<textarea id="description" wire:model="product.description" rows="3" class="form-textarea mt-1 block w-full transition duration-150 ease-in-out sm:text-sm sm:leading-5"></textarea>
</div>
</div>
</div>
</div>
<div class="px-4 py-3 bg-gray-50 text-right sm:px-6">
<span class="inline-flex rounded-md shadow-sm">
<button type="submit" class="inline-flex justify-center py-2 px-4 border border-transparent text-sm leading-5 font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-500 focus:outline-none focus:border-indigo-700 focus:shadow-outline-indigo active:bg-indigo-700 transition duration-150 ease-in-out">
Update
</button>
</span>
</div>
</form>
</div>
</div>
</div>
#include('spacer')
<div class="md:grid md:grid-cols-3 md:gap-6">
<div class="md:col-span-1">
<div class="px-4 sm:px-0">
<h3 class="text-lg font-medium leading-6 text-gray-900">Categories</h3>
</div>
</div>
<div class="mt-5 md:mt-0 md:col-span-2">
<div class="shadow sm:rounded-md sm:overflow-hidden">
<table class="min-w-full divide-y divide-gray-200">
<thead>
<tr>
<x-th>Title</x-th>
<x-th>Enable/Disable</x-th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
#foreach($categories as $category)
<tr>
<td class="px-6 py-4 whitespace-no-wrap">
<div class="flex items-center">
<div class="text-sm font-medium text-gray-900">
{{ $category->title }}
</div>
</div>
</td>
<td class="px-6 py-4 whitespace-no-wrap">
<div class="mt-1 flex rounded-md">
<span role="checkbox" tabindex="0" aria-checked="false" class="#if($enabled) bg-indigo-600 #else bg-gray-200 #endif relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:shadow-outline">
<span aria-hidden="true" class="#if($enabled) translate-x-5 #else translate-x-0 #endif inline-block h-5 w-5 rounded-full bg-white shadow transform transition ease-in-out duration-200">
<input id="enabled" type="checkbox" wire:model="enabled" class="invisible">
</span>
</span>
</div>
</td>
</tr>
#endforeach
</tbody>
</table>
</div>
</div>
</div>
</div>
If you check the documentation for Livewire, at lifecycle hooks... you will see that:
mount : Runs once, immediately after the component is instantiated, but before render() is called
So basically you are getting an "enabled" value once, before rendering the component,then you start rendering it, with that foreach, using the same "enabled" from mount for each item of your dataset.
Consider building your cursor with the enabled value inside for each record.

How to fix a strange behaviour with laravel livewire and pagination?

I started with Laravel 8 and livewire a few days ago. I still have a lot to discover but I am on my way.
Lastly, I encountered a behaviour I have trouble understanding.
My goal
I want to create a page to CRUD posts. What I want is to have a post list that is paginated displayed at the bottom of the page, a button to create a new post and the possibility to click a button on each post line to edit the post.
I also want the editor of the post displayed at the top of the page while the list is hidden (but this last possibility is not absolutely necessary).
I could manage to have this working as long as the post list is not paginated but not with pagination.
To do this I use a liveewire component whose code is herebelow:
Component's code in app/Http/livewire/posts/Posts.php
<?php
namespace App\Http\Livewire\Posts;
use App\Models\Post;
use Livewire\Component;
class Posts extends Component
{
public $posts;
public $links;
public $post_id,$title, $abstract, $body,$category,$diaporama_dir,
$beg_date,$end_date,$close_date,$receive_registration,
$sticky,$user_id,$inscription_directive;
/**
* The attributes that are mass assignable.
*
* #var array
*/
public function render()
{
$this->mode='list';
$this->posts=Post::select('id','title')->orderBy('created_at','DESC')->paginate(15)->toArray();
$this->links=$this->posts['links'];
//dd($this->links);
$this->user_id=auth()->user()->id;
return view('livewire.posts.posts');
}
public function donothing(){
}
/*
* The attributes that are mass assignable.
*
* #var array
*/
public function resetInputFields(){
$this->title = '';
$this->body = '';
$this->title='';
$this->abstract='';
$this->body='';
$this->category='';
$this->diaporama_dir='';
$this->beg_date='';
$this->end_date='';
$this->close_date='';
$this->receive_registration='';
$this->sticky='';
$this->inscription_directive='';
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
public function store()
{
$validatedData = $this->validate([
'title' => 'required',
'body' => 'required',
'abstract'=>'required',
'category'=>'',
'diaporama_dir'=>'',
'beg_date'=>'sometimes',
'end_date'=>'sometimes',
'close_date'=>'sometimes',
'receive_registration'=>'',
'sticky'=>'',
'user_id'=>'required',
'inscription_directive'=>''
]);
Post::create($validatedData);
session()->flash('message', 'Bravo ! Votre article a été enregistré.');
// $this->resetInputFields(); //user may want to keep the input stable
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
public function edit($id)
{
$post = Post::findOrFail($id);
$this->post_id = $id;
$this->title = $post->title;
$this->abstract=$post->abstract;
$this->body=$post->body;
$this->category=$post->category;
$this->diaporama_dir=$post->diaporama_dir;
$this->beg_date=$post->beg_date;
$this->end_date=$post->end_date;
$this->close_date=$post->close_date;
$this->receive_registration=$post->receive_registration;
$this->sticky=$post->sticky;
$this->inscription_directive=$post->inscription_directive;
$this->dispatchBrowserEvent('notify','je passe en mode edit');//to switch browser page to edit mode
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
public function update()
{
$validatedData = $this->validate([
'title' => 'required',
'body' => 'required',
'abstract'=>'required',
'category'=>'',
'diaporama_dir'=>'',
'beg_date'=>'sometimes',
'end_date'=>'sometimes',
'close_date'=>'sometimes',
'receive_registration'=>'',
'sticky'=>'',
'user_id'=>'required',
'inscription_directive'=>''
]);
$post = Post::find($this->post_id);
$post->update([
'title' => $this->title,
'body'=> $this->body,
'abstract'=> $this->abstract,
'category'=> $this->category,
'diaporama_dir'=>$this->diaporama_dir,
'beg_date'=>$this->beg_date,
'end_date'=>$this->end_date,
'close_date'=>$this->close_date,
'receive_registration'=>$this->receive_registration,
'sticky'=>$this->sticky,
'user_id'=>$this->user_id,
'inscription_directive'=>$this->inscription_directive
]);
session()->flash('message', "Bravo ! L'article a été mis à jour.");
// $this->resetInputFields();//user may like to keep the input fields stable
}
}
and views are these:
View 1 : the main page in resources/views/livewire/posts/posts.blade.php
<div class="container m-auto w-10/12">
<div x-data="{ mode: 'list' }">
#if (session()->has('message'))
<div class="bg-green-200 p-4 w-full my-8 text-xl text-orange-500">
{{ session('message') }}
</div>
#endif
<div x-on:notify.window="mode = 'update'">
<div x-show="mode==='update'">
#include('livewire.posts.update')
</div>
<div x-show="mode === 'edit'">
#include('livewire.posts.create')
</div>
</div>
{{-- <div x-show="mode === 'list'" class="">--}}
<div>
<div>
<button x-on:click="mode = 'edit'" class="bg-red-400 px-2 py-1 border rounded-lg mt-2">Nouvel
article</button>
</div>
<table class=" bg-green-400 w-full table table-bordered mt-5 ">
<thead>
<tr class="bg-red-50 mb-2">
<th>Id.</th>
<th>Titre</th>
<th width="150px">Action</th>
</tr>
</thead>
<tbody>
#for ($i = 0; $i < $posts['per_page']; $i++)
<tr class="bg-red-400 mb-2 p-2 space-y-2 border-8 border-red-50 ">
<td>{{ $posts['data'][$i]['id'] }}</td>
<td>{{ $posts['data'][$i]['title'] }}</td>
<td>{{--les actions--}}
<button wire:click="edit({{ $posts['data'][$i]['id'] }})"
class="btn btn-primary btn-sm">Edit</button>
{{-- <button wire:click="delete({{ $post->id }})"
class="btn btn-danger btn-sm">Delete</button>--}}
</td>
</tr>
#endfor
</tbody>
</table>
<div class="flex flex-row mt-2">
#for ($i = 0; $i < count($links); $i++)
<div class="flex p-2 mr-2 border w-max-content">
{{$links[$i]['label']}}
</div>
#endfor
</div>
</div>
</div>
2- create include in resources/views/livewire/posts/create.blade.php
<div class="container bg-green-500 p-4">
<form>
This is the create form
<input type="hidden" name="user_id" wire:model="user_id" >
<div class="flex flex-col md:flex-row" >
<div class=" mt-2 flex flex-col w-max-content">
<label for="category">Catégorie:</label>
<select class="" name="category" id="category" wire:model="category">
<option value="Sans">Sans</option>
<option value="Annoncement">Annonce d'un événement</option>
</select>
#error('category') <span class="text-danger">{{ $message }}</span>#enderror
</div>
<div class=" mt-2 flex flex-col flex-auto ml-4">
<label for="title">Title:</label>
<input type="text" class="form-control" name="title" id="title" placeholder="Saisissez un titre"
wire:model="title" value="">
#error('title') <span class="text-danger">{{ $message }}</span>#enderror
</div>
</div>
<div class="flex flex-col md:flex-row" >
<div class=" mt-2 flex flex-col w-max-cbeg_date ">
<label for="beg_date">Date de début</label>
<input type="text" class="" name="beg_date" id="beg_date" wire:model="beg_date">
#error('beg_date') <span class="text-danger">{{ $message }}</span>#enderror
</div>
<div class=" mt-2 flex flex-col w-max-cbeg_date ml-4">
<label for="end_date">Datend_date</label>
<input type="text" class="" name="end_date" id="end_date" wire:model="end_date">
#error('end_date') <span class="text-danger">{{ $message }}</span>#enderror
</div>
<div class=" mt-2 flex flex-col w-max-cbeg_date ml-4">
<label for="close_dclose">Date limite</label>
<input type="text" class="" name="close_date" id="close_date" wire:model="close_date">
#error('close_date') <span class="text-danger">{{ $message }}</span>#enderror
</div>
<div class=" mt-2 flex flex-col w-max-content ml-4">
<label for="receive_registration">Accepte les inscriptions:</label>
<select class="" name="receive_registration" id="receive_registration" wire:model="receive_registration">
<option value="no">Non</option>
<option value="yes">Oui</option>
</select>
#error('receive_registration') <span class="text-danger">{{ $message }}</span>#enderror
</div>
<div class=" mt-2 flex flex-col flex-auto ml-4">
<label for="title">Dossier du diaporama</label>
<input type="text" class="form-control" name="diaporama_dir" id="diaporama_dir" placeholder="ex: admin/1"
wire:model="diaporama_dir">
#error('diaporama_dir') <span class="text-danger">{{ $message }}</span>#enderror
</div>
</div>
<div class="mt-2 flex flex-col">
<label for="abstract">Résumé</label>
<textarea class="form-control" name="abstract" id="abstract" wire:model="abstract"
placeholder="Saisissez votre article"></textarea>
#error('abstract') <span class="text-danger">{{ $message }}</span>#enderror
</div>
<div class="mt-2 flex flex-col">
<label for="body">Corps de l'article</label>
<textarea class="form-control" name="body" id="body" wire:model="body" rows=30
placeholder="Saisissez votre article"></textarea>
#error('body') <span class="text-danger">{{ $message }}</span>#enderror
</div>
<button wire:click.prevent="store()" class="bg-red-400 px-2 py-1 border rounded-lg mt-2">Enregistrer</button>
<button wire:click.prevent="resetInputFields()" class="bg-red-400 px-2 py-1 border rounded-lg mt-2">Effacer tout</button>
<button #click.prevent="mode = 'list'" class="bg-red-400 px-2 py-1 border rounded-lg mt-2 ml-16">Retour à la liste</button>
</form>
update include
The update include is exactly the same as the create include except an additional hidden field for the post id.
What is happening?
At startup, I mean when I visit the localhost:8000/posts page, the page 1 is correctly displayed and the links at the bottom of the page are like localhost:8000/posts?page=3 whichever the number of the page may be.
From this page I can normally go to another page using the bottom links, and this several times.
The troube arises when I click a link to edit a post. The post is correctly sent back by the server but instantly we are switched to page 1 of the paginated posts and the bottom links take a strange form such as localhost:8000/livewire/message/posts.posts?page=3 wichever the page number may be.
The trouble arises also when, after having displayed the create form, I type a first char in the fields. In fact it seems that it arises each time a sync is required.
How can I fix this?
replace
<div class="flex flex-row mt-2">
#for ($i = 0; $i < count($links); $i++)
<div class="flex p-2 mr-2 border w-max-content">
{{$links[$i]['label']}}
</div>
#endfor
</div>
with
<div class="flex flex-row mt-2">
{{ $posts->links() }}
</div>
and in component
use WithPagination;
ref link https://laravel-livewire.com/docs/2.x/pagination

Laravel PATCH works on update but validation in controller fails

I am following along with the Laracast lab, the Tweety feed and all was going good until i hit a wall.
I have a PATCH to update the user profile and it works and updates the record, but the validation doesn't. The form submits if fully complete and the record is fine but if the form validation fails server side in my controller, I get as below:
Symfony\Component\HttpKernel\Exception\MethodNotAllowedHttpException
The GET method is not supported for this route. Supported methods: POST.
I have looked at the FAQ section here and scoured the net already asked and tried several steps to sort this. I have tried:
Using $user->username in my edit file template and controller.
Changing the route from PATCH TO PUT (and also POST, simply using store)
Checking the User model and ensuring I am using 'getRouteKeyName' working correctly, it is.
Checking if there is a conflict in the route, there is none and the order/VERB is fine.
Can anyone please help? Below is my code.
Routes as below:
// Snippet for seeing all the database queries.
//DB::listen(function($query){var_dump($query->sql, $query->bindings);});
use Illuminate\Support\Facades\Route;
// Home view, no sign-in required.
Route::get('/', function () {
return view('welcome');
});
// These routes require and use auth middleware.
Route::middleware('auth')->group(function(){
// TWeets main page.
Route::get('/tweets/', 'TweetsController#index')->name('home');
// Store a new tweet
Route::post('/tweets/', 'TweetsController#store');
// Profile area, view and update
// Use the 'name' attribute in route/model binding instead of the primary key = user:name
Route::get('/profile/{user:username}/', 'ProfileController#show')->name('profile');
// Show form to edit the profile
Route::post('/profile/{user:username}/edit','ProfileController#edit')->name('edit_profile');
//->middleware('can:edit,user'); // Don't forget the wildcard.
// Finally, update the users profile information.
Route::patch('/profile/{user:username}','ProfileController#update')->name('update_profile');
// Handles the follow/unfollow on a toggle method.
Route::post('/profile/{user:username}/follow/','FollowsController#store');
// Logs you out & directs to the homepage.
Route::get('/logout', '\App\Http\Controllers\Auth\LoginController#logout');
});
Auth::routes();
Controller as below:
/**
* Update the users profile after validation
*
* #param \Illuminate\Http\Request $request
* #param int $id
* #return \Illuminate\Http\Response
*/
public function update(User $user)
{
$validated = request()->validate([
'name'=>'required',
'username'=>'required',
'password'=>'required',
'password_confirmation'=>'required',
]);
$user->update($validated);
// Redirect to the tweets page which is called 'home'.
return redirect(route('profile', $user->username));
}
Template:
<x-app>
<form class="w-full" method="POST" action="{{route('update_profile',$user)}}">
#method('PATCH')
#csrf
<h2 class="text-xl mb-2 py-4 font-bold">Edit profile for {{$user->username}}</h2>
<p class="text-sm mb-5 mt-0">Below you an update your profile details.</p>
<div class="flex flex-wrap -mx-3 mb-6">
<div class="w-full px-3 mb-6 md:mb-0">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-name">Name</label>
<input class="appearance-none block w-full bg-gray-200 text-gray-700 border border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" id="name" type="text" placeholder="Mike Smith.." name="name" value="{{$user->name}}"/>
</div>
#error('name')
<p>{{$message}}</p>
#enderror
<div class="w-full px-3 mb-6 md:mb-0">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-username">Username</label>
<input class="appearance-none block w-full bg-gray-200 text-gray-700 border border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" id="grid-username" type="text" placeholder="MikeSmith1..." name="username" value="{{$user->username}}"/>
</div>
#error('username')
<p>{{$message}}</p>
#enderror
<div class="w-full px-3 mb-6 md:mb-0">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-username">Email</label>
<input class="appearance-none block w-full bg-gray-200 text-gray-700 border border-red-500 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white" id="grid-username" type="email" placeholder="MikeSmith#yahoo.com..." name="email" value="{{$user->email}}"/>
</div>
#error('email')
<p>{{$message}}</p>
#enderror
<div class="w-full px-3">
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-password">Password</label>
<input class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" id="grid-password" type="password" name="password"/>
<p class="mb-3 text-red-600 text-xs italic">Make it as long and as crazy as you'd like</p>
</div>
<div class="w-full px-3"> {{-- This HAS to be called "password_confirmation" --}}
<label class="block uppercase tracking-wide text-gray-700 text-xs font-bold mb-2" for="grid-password">Password Confirmation</label>
<input class="appearance-none block w-full bg-gray-200 text-gray-700 border border-gray-200 rounded py-3 px-4 mb-3 leading-tight focus:outline-none focus:bg-white focus:border-gray-500" id="grid-password_confirmation" type="password" name="password_confirmation"/>
</div>
<button type="submit" class="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 ml-2 mt-4 px-4 rounded">
Update details
</button>
</div>
</form>
</x-app>
Model:User
/**
* Laravel <=6 - use this method, after v6, you can do this on the route itself.
* Using this so we can use a user name in the route, instead of the ID Laravel normally uses for route/model binding. Now you can use /profile/mikethornley
* This will still enable route/model binding to work and still find the user
* #return [type] [description]
*/
public function getRouteKeyName()
{
return 'username';
}
This is the problem:
// Use the 'name' attribute in route/model binding instead of the primary key = user:name
Route::get('/profile/{user:username}/', 'ProfileController#show')->name('profile');
// Finally, update the users profile information.
Route::patch('/profile/{user:username}','ProfileController#update')->name('update_profile');
Your routes are clashing... that post ends up in the show() method and that's why you get the error.
You need to make some change in that post route if you want to have parameters. For example
Route::patch('/profile-update/{user:username}','ProfileController#update')->name('update_profile');

Resources