Building own Datatable with Laravel 10 and livewire 3
In this tutorial, we will walk through the process how to create own dynamic datatable with Laravel 10 and livewire 3. Let’s build it from scratch!
(This tutorial is still in draft; updates will be provided as soon as possible 😴)
Prerequisites
Before proceeding, make sure you have the following requirements:
- Php installed on your local machine (version 8.0 or higher)
- Composer
- Basic understanding php
- Familiarity with laravel and livewire (previous versions)
Setup a project
Before we start, in this tutorial I will use jetStream and livewire, so make sure you follow the step by step. Open your terminal, and type
composer create-project laravel/laravel datatable-app
you can use any project name based on your project. This command will create project named “datatable-app”. Wait for the installation completed.
Once your project installed, install the Jetstream package. Make sure terminal on path datatable-app.
> Cd datatable-app
datatable-app > composer require Laravel/jetstream
After install Jetstream package, you need to install livewire with this command:
php artisan jetstream:install livewire
Why choose Jetstream as the foundation for our project? Jetstream provides a pre-built UI package for our project, eliminating the need for us to set up the UI from scratch in the initial stages of the project.
Database configuration
Next, open your project and navigate to .env file. If .env file not exist, you can create with command:
cp .env.example .env
It will copy the .env.example and rename it with .env .
Navigate to your .env file and update the database name. Ensure that you have started the database, and you can choose between Laragon or MySQL, it’s free to choose. Replace the database name with your preferred choice.
DB_DATABASE = your_db_name
Save the changes and close the file.
Finalizing the installation
After configuring the database, proceed to install and build your NPM dependencies, and then migrate your database by running:
npm install
npm run build
php artisan migrate
make sure you follow the command from top to bottom. if there’s no error, congrats you already setup the project correctly.
Create Livewire Component and Resources
Since this is not a package, this tutorial will guide you through the process of creating a Livewire component to optimize the functionality of the datatable component.
Create a livewire component called customer
. Then create database customers and the model. You can follow commands below.
php artisan make:livewire Customers
php artisan make:migration create_customers_table
php artisan make:model Customer
The commands will generate 3 files on model, livewire and also migrations folder.
First open file create_customers_table
and add some columns for the table.
public function up(): void
{
Schema::create('customers', function (Blueprint $table) {
$table->id();
$table->string('code', 10);
$table->string('name');
$table->string('email');
$table->string('phone',16);
$table->text('address');
$table->string('country');
$table->timestamps();
});
}
Runphp artisan migrate
. Then, open your customer model and add the following codes.
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Customer extends Model
{
use HasFactory;
protected $table = 'customers';
protected $guarded = [];
public function scopeSearch($query, $value){
$query->where("name", "like", "%{$value}%");
}
}
The scopeSearch
function will be utilized as the livewire search mechanism in our datatable components.
Next step, open the Customer livewire component then add the following codes:
<?php
namespace App\Livewire;
use App\Models\Customer;
use Livewire\Attributes\On;
use Livewire\Component;
use Illuminate\Validation\ValidationException;
use Livewire\WithPagination;
class Customers extends Component
{
use WithPagination;
public $isModalOpen = false;
public $isModalDelete = false;
public $isUpdatePage = false;
public $page = 1;
public $perPage = 10;
public $search = '';
public $sortDirection = 'DESC';
public $sortColumn = 'created_at';
public $confirmDeleteId;
/**
* Toggle sort direction when column header is clicked.
*
* @param string $column
* @return void
*/
public function doSort($column)
{
if ($this->sortColumn === $column) {
$this->sortDirection = ($this->sortDirection === 'ASC') ? 'DESC' : 'ASC';
return;
}
$this->sortColumn = $column;
$this->sortDirection = 'ASC';
}
/**
* Store the current page when updating.
*
* @param int $page
* @return void
*/
public function updatingPage($page)
{
$this->page = $page ?: 1;
}
/**
* Save the current page to the session.
*
* @return void
*/
public function updatedPage()
{
session(['page' => $this->page]);
}
/**
* Initialize component with stored page or default values.
*
* @return void
*/
public function mount()
{
if (session()->has('page')) {
$this->page = session('page');
}
}
/**
* Render the data on the customer table.
*
* @return \Illuminate\Contracts\View\View
*/
public function render()
{
$columns = [
['label' => 'Code', 'column' => 'code', 'isData' => true,'hasRelation'=> false],
['label' => 'Customer Name', 'column' => 'name', 'isData' => true,'hasRelation'=> false],
['label' => 'Email', 'column' => 'email', 'isData' => true,'hasRelation'=> false],
['label' => 'Phone', 'column' => 'phone', 'isData' => true,'hasRelation'=> false],
['label' => 'Address', 'column' => 'address', 'isData' => true,'hasRelation'=> false],
['label' => 'Country', 'column' => 'country', 'isData' => true,'hasRelation'=> false],
['label' => 'Action', 'column' => 'action', 'isData' => false,'hasRelation'=> false],
];
$customers = Customer::search($this->search)
->orderBy($this->sortColumn, $this->sortDirection)
->paginate($this->perPage, ['*'], 'page');
return view('livewire.customers.index', compact('customers', 'columns'));
}
public function customFormat($column, $data)
{
switch ($column) {
case 'created_at':
$parsedDate = \Carbon\Carbon::parse($data);
return $parsedDate->diffForHumans();
default:
return $data;
}
}
/**
* Open the modal popover based on the provided ID.
*
* @param int|null $id
* @return void
*/
public function openModalPopover($id = null)
{
if ($id) {
$this->confirmDeleteId = $id;
$this->isModalDelete = true;
} else {
$this->isModalOpen = true;
}
}
/**
* Close the modal popover.
*
* @return void
*/
public function closeModalPopover()
{
$this->isModalDelete = false;
$this->isModalOpen = false;
$this->resetCreateForm();
}
}
Create Datatable Components
Before delving into these components, take a look at the component structure in the folder. You can simply create the component file there. Before initiating the component creation process, it’s essential to define the components required for the datatable.
In my tutorial, I’ve divided the datatable component into five separate components.
- Table: Used as the parent component for all other components.
- Table Body: Responsible for setting the values of each table row.
- Table Row: Represents each individual item’s value in a row.
- Table Head: Used to define and set the column data.
- Datatable Column: Allows for customization of the column header.
In this tutorial, we will begin the implementation process starting from the smallest component and gradually progress to the largest.
Datatable Column
Create the component calleddatatable-column.blade.php
This component serves as a visual representation of a sortable column within a Livewire DataTable. It dynamically displays an icon indicating the current sorting direction, either ascending or descending, providing a user-friendly interface for sorting data in Laravel applications.
Table Head
Create component calledtable-head.blade.php
In this code, you might observed the purpose of$value['isData’]
. The $value['isData']
function is used to determine whether a specific column should be treated as a data column. If a column is designated as a data column, it gets a special treatment with a sortable header and the inclusion of the 'datatable-column' Livewire component. If it's not a data column, a regular header is generated. The purpose of this function is to distinguish between columns meant for data sorting and those that are not. all the properties in the above code will be passed from the parent component.
Table Row
Create component called table-row.blade.php
Okay, let’s breakdown the component by the props.
item,key,page,PerPage
: Used as the counter for numbering data. these variables synchronize with the pagination functionality generated by Laravel itself.columns
: Used as displaying the data.
Table Body
Create component called table-body.blade.php
Table
Create component called table.blade.php
View Customer
Create view file called index.blade.php
inside a folder livewire/customer.