Skip to main content
Premium Members Only
Join to unlock this tutorial and all of our courses.
Premium Tutorial

Livewire 3 CRUD with Form Objects and Modal Wire Elements

September 11, 2023
10 min read

Livewire v3 introduced Form Objects to offload the field logic from the Component. In this tutorial, we'll build the create/edit modal forms powered by the Wire Elements package and reuse the same Livewire component and Form Object.

modal with unique rule


Preparation: Laravel Project

For the Laravel project visual design, we will use our own starter kit Laravel Breeze Pages Skeleton.

In the Model Product we will have two DB fields: name and description.

database/migrations/xxx_create_products_table.php:

public function up(): void
{
Schema::create('products', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->text('description');
$table->timestamps();
});
}

app/Models/Product.php:

class Product extends Model
{
protected $fillable = [
'name',
'description',
];
}

Install Livewire and Customize Breeze

First, of course, we need to install install Livewire.

composer require livewire/livewire

Next, because Alpine.js is baked into the core of Livewire, we need to remove it from our Breeze-powered skeleton. If you don't use Laravel Breeze, you can skip this step.

resources/js/app.js:

import './bootstrap';
 
import Alpine from 'alpinejs';
 
window.Alpine = Alpine;
 
Alpine.start();

And recompile assets.

npm run prod

The last thing is changing the main layout path.

Livewire looks for a layout in resources/views/components/layouts/app.blade.php, but our Breeze-based Starter kit has it in a different place, so we need to set it in the Livewire config.

php artisan livewire:publish --config

config/livewire.php:

return [
// ...
'layout' => 'components.layouts.app',
'layout' => 'layouts.app',
// ...
];

And that's it, we can use Livewire in our project. Now, let's create a Livewire component to show the products list.


Livewire Component: Products List

php artisan make:livewire ProductList

app/Livewire/ProductList.php:

use App\Models\Product;
use Illuminate\Contracts\View\View;
 
class ProductList extends Component
{
public function render(): View
{
return view('livewire.product-list', [
'products' => Product::all(),
]);
}
}

Let's add a link to the navigation and show the products table.

resources/views/layouts/navigation.blade.php:

// ...
 
<div class="hidden space-x-8 sm:-my-px sm:ml-10 sm:flex">
<x-nav-link :href="route('users.index')" :active="request()->routeIs('users.index')">
{{ __('Users') }}
</x-nav-link>
<x-nav-link :href="route('products')" :active="request()->routeIs('products')">
{{ __('Products') }}
</x-nav-link>
</div>
 
// ...

resources/views/livewire/product-list.blade.php:

<div>
<x-slot name="header">
<h2 class="text-xl font-semibold leading-tight text-gray-800">
{{ __('Products') }}
</h2>
</x-slot>
 
<div class="py-12">
<div class="mx-auto max-w-7xl sm:px-6 lg:px-8">
<div class="overflow-hidden bg-white shadow-sm sm:rounded-lg">
<div class="p-6 overflow-hidden overflow-x-auto bg-white border-b border-gray-200">
 
<div class="min-w-full align-middle">
<table class="min-w-full border divide-y divide-gray-200">
<thead>
<tr>
<th class="px-6 py-3 text-left bg-gray-50">
<span class="text-xs font-medium leading-4 tracking-wider text-gray-500 uppercase">Name</span>
</th>
<th class="px-6 py-3 text-left bg-gray-50">
<span class="text-xs font-medium leading-4 tracking-wider text-gray-500 uppercase">Description</span>
</th>
<th class="px-6 py-3 text-left bg-gray-50">
</th>
</tr>
</thead>
 
<tbody class="bg-white divide-y divide-gray-200 divide-solid">
@forelse($products as $product)
<tr class="bg-white">
<td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
{{ $product->name }}
</td>
<td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
{{ $product->description }}
</td>
<td class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
{{-- Edit Button --}}
</td>
</tr>
@empty
<tr class="bg-white">
<td colspan="3" class="px-6 py-4 text-sm leading-5 text-gray-900 whitespace-no-wrap">
No products found.
</td>
</tr>
@endforelse
</tbody>
</table>
</div>
 
</div>
</div>
</div>
</div>
</div>

products table


Modal with Form Object

Now, let's create a component that will be a modal and...

Premium Members Only

This advanced tutorial is available exclusively to Laravel Daily Premium members.

Premium membership includes:

Access to all premium tutorials
Video and Text Courses
Private Discord Channel
Rajesh Budhathoki avatar

The Git repo link is not working!

adithyaricky avatar

maybe mr pivolas forget to make it public. this repo are similar https://github.com/LaravelDaily/Livewire-3-Course-Demo

Nerijus avatar

@adithyaricky your mentioned is public

Rajesh Budhathoki avatar

I've identified errors in the tutorial, and my code isn't functioning correctly. I'd like to access the source code. Could you please correct the link as soon as possible?

Nerijus avatar

Will be fixed today

Nerijus avatar

Now it's public

👍 1
Masstech avatar

i don't see the link for the video. Do you have video tutorial of this topic ?

Nerijus avatar

Povilas have plenty videos on YouTube about livewire

Rajesh Budhathoki avatar

Dear Povilas, I noticed an issue in your code within the app/Livewire/ProductModal.php file. It appears that there is an incorrect view being used inside the render() method. Similarly, there seems to be a filename discrepancy in resources/views/livewire/product-form.blade.php, possibly causing issues.

I cloned your code and tested the application, but it doesn't seem to open the modal as expected.

I've had a somewhat frustrating experience with the course "Livewire 3 From Scratch: Practical Course." As a result, I decided to jump into this CRUDy article to fill in the gaps in my understanding of Livewire. However, I found myself facing similar challenges with this article as well. I'm hoping there's a beginner-friendly CRUDy course available for Livewire v3 that can help me grasp the concepts more effectively. Thank you for your assistance!

Thakchand avatar

Add

@livewire('wire-elements-modal')

inside the body section of resources/views/layouts/app.blade.php

Thakchand avatar

resources/views/livewire/product-form.blade.php

should be kept as

resources/views/livewire/product-modal.blade.php

Bradley Miller avatar

Can you show the navigation link when collapsed code also? The demo is fine on a computer but I have no links when on mobile?

Nerijus avatar

You need to add them in the navigation.blade.php

Bradley Miller avatar

The example shows the navigation but it didn't put it into the drop-link area.

Nerijus avatar

Yes because we aren't building a full app. It's just to show a concept how to do something. If you need to links for mobile feel free to do that it's in the same

Rogerio Picilli avatar

It appears that this step-by-step guide is missing some information. I'm not sure if it's intentional to encourage research and learning, or if it's simply an oversight. First, what are the routes? Are we using Controllers to call the Livewire pages/components, or are we calling them directly without the use of controllers? How are Data Models being passed to the view?

I am a subscriber to this website, but sometimes I struggle to make the examples work."

Nerijus avatar

For this tutorial no contdollera are used this is a full page component. For data the route model binding is being used. Also the source code is available you can check

Thakchand avatar

define route in web.php as Route::get('/products', ProductList::class)->name('products');

Richard A. Hoyle avatar

Can you please Redo this Tutorial using the 2.0.7 version of LivewireUI\Modal\ModalComponent I just can not get this Tutorial to work It is to outdated. not even your Github Repository will work for me.

Nerijus avatar

This is a new tutorial only a month old and uses the 2.o.7 version of wire-elements/modal.

Zoltan Farkas avatar

Hy! I would like to replace the listing section in the description with the Livewire PowerGrid listing. Is there a description available regarding this? Thank you.

Nerijus avatar

No, we don't have any tutorials using powergrid. Maybe Povilas has a YouTube video. Just check their docs

Zoltan Farkas avatar

Okay, thank you.

Zoltan Farkas avatar

Will there be a solution for the delete function in the near future?

Nerijus avatar

What do you need about it? Create a delete method and pass id to it. In that method delete. There are a couple livewire courses that do this.

Dmytro Sakharuk avatar

Then in the title of the article in the CRUD acronym you need to remove the letter D :)

Joshua Lictan avatar

How to adjust the width or size of the modal

<div class="overflow-x-auto">
<table class="min-w-full bg-white divide-y divide-gray-200">
<thead>
<tr>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Category
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Total
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Reserved
</th>
<th class="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">
Available
</th>
</tr>
</thead>
<tbody class="bg-white divide-y divide-gray-200">
<!-- Example row (repeat for each item) -->
<tr>
<td class="px-6 py-4 whitespace-nowrap">
<!-- Category value -->
</td>
<td class="px-6 py-4 whitespace-nowrap">
<!-- Total value -->
</td>
<td class="px-6 py-4 whitespace-nowrap">
<!-- Reserved value -->
</td>
<td class="px-6 py-4 whitespace-nowrap">
<!-- Available value -->
</td>
</tr>
<!-- Add more rows as needed... -->
</tbody>
</table>
</div>

i have design here that table is horizontally scrollable how to make it reponsive

Nerijus avatar

For modal refer to the docs of the package. For table you will need to learn CSS.

Joshua Lictan avatar

no matter what i do to my modal it will not change its width, do i need the pro version?

i already did public static function modalMaxWidth(): string { return '2xl'; }

Modestas avatar

Did you compile your assets after changin the width?

Keep in mind: With any css changes you need to run npm run build to compile them into "available" assets, otherwise - no class will be added.

Nerijus avatar

Just adding a method like that shouldn't change the width if tailwind doesn't compile that class. Check the docs this part https://github.com/wire-elements/modal#building-tailwind-css-for-production

Joshua Lictan avatar

fixed it, the problem is the minimum width not the maximum

Bruno Pincaro avatar

having the same problem with modal width. how did you solve yours with minimum width ?

Nerijus avatar

Refer to package documentation

xvlros avatar

Perhaps a general question about Laravel model methods, but how would one verify the $model->update() (or $model->save) / $model->delete() worked and then send that back to the Livewire component for confirmation?

We'd Love Your Feedback

Tell us what you like or what we can improve

Feel free to share anything you like or dislike about this page or the platform in general.