Building own Datatable with Laravel 10 and livewire 3

Haikal rahmadi
6 min readJan 14, 2024

--

souce: khrisnaweb.com

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 scopeSearchfunction 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.

--

--