Courses

Livewire 3 From Scratch: Practical Course

Edit Product Form: Reusable Form Object?

Summary of this lesson:
- Creating separate edit component
- Implementing form objects pattern
- Managing shared validation rules
- Extracting common form logic

We have made a create page. Now we need a page for editing records. Forms can be made in two ways. The first one, make a new component and add everything, or the second, extract parts in the Form Object.


Separate Component

First, we need a new component and a route mapped to it. Then we can link the edit button to that route.

php artisan make:livewire ProductsEdit

routes/web.php:

Route::get('products', [\App\Http\Controllers\ProductController::class, 'index']);
Route::get('products/create', \App\Livewire\ProductsCreate::class)->name('products.create');
Route::get('products/{product}/edit', \App\Livewire\ProductsEdit::class)->name('products.edit');

resources/views/livewire/products.blade.php:

<div class="space-y-6">
// ...
<td>
<a href="{{ route('products.edit', $product) }}" class="inline-flex items-center px-4 py-2 bg-gray-800 rounded-md font-semibold text-xs text-white uppercase tracking-widest">
Edit </a>
<a wire:click="deleteProduct({{ $product->id }})" onclick="return confirm('Are you sure?') || event.stopImmediatePropagation()" href="#" class="inline-flex items-center px-4 py-2 bg-red-600 rounded-md font-semibold text-xs text-white uppercase tracking-widest">
Delete </a>
</td>
// ...
</div>

The form itself is the same as for the create product.

resources/views/products-edit.blade.php:

<form method="POST" wire:submit="save">
<div>
<label for="name" class="block font-medium text-sm text-gray-700">Name</label>
<input id="name" class="block mt-1 w-full border-gray-300 rounded-md shadow-sm" type="text" wire:model="name" />
@error('name')
<span class="mt-2 text-sm text-red-600">{{ $message }}</span>
@enderror
</div>
 
<div class="mt-4">
<label for="description" class="block font-medium text-sm text-gray-700">Description</label>
<textarea id="description" class="block mt-1 w-full border-gray-300 rounded-md shadow-sm" wire:model="description"></textarea>
@error('description')
<span class="mt-2 text-sm text-red-600">{{ $message }}</span>
@enderror
</div>
 
<div class="mt-4">
<label for="category">Category</label>
<select wire:model="category_id" name="category" id="category" class="block mt-1 w-full border-gray-300 rounded-md shadow-sm">
<option value="0">-- CHOOSE CATEGORY --</option>
@foreach($categories as $id => $category)
<option value="{{ $id }}">{{ $category }}</option>
@endforeach
</select>
@error('category_id')
<span class="mt-2 text-sm text-red-600">{{ $message }}</span>
@enderror
</div>
 
<button class="mt-4 px-4 py-2 bg-gray-800 rounded-md font-semibold text-xs text-white uppercase tracking-widest hover:bg-gray-700">
Save Product
</button>
</form>

In the Livewire components class, first, we need to assign all the properties to values from the product. Because we are using Route Model Binding, we can accept Product parameter in the...

The full lesson is only for Premium Members.
Want to access all 30 lessons of this course? (108 min read)

You also get:

  • 69 courses (majority in latest Laravel 11)
  • Premium tutorials
  • Access to repositories
  • Private Discord