Have you ever noticed, the datatable renders only visible rows in the DOM? That means if you have any events triggering inside the datatable rows, it will work for the visible pages only. The reason is whatever is rendered on the first page will be added to the DOM tree. If you try to submit all the rows from the datatable then it will push only first-page rows. This is because, in the DOM tree, only the visible rows are rendered. So, on form submission, it will pass only those visible rows. But, how can you pass all rows which are rendered next to the first page?
Today, through this post, I will show you one of the solutions for datatable form handling. So, let’s dive into the post to implement this functionality.
Prerequisites
For implementing this datatable form handling in Laravel, you need to the below configurations. Here, I will be using Laravel 9.
- PHP >=8.0.2
- Composer
- Apache/Nginx Server
- VS Code Editor (Optional)
- MySQL (version > 5)
Now, let’s jump to the first step of the project setup.
How to Implement Repository Design Pattern in Laravel 9
Create a Laravel Project For Datatable Form Handling
For creating a project, I will use composer. You can open the terminal and create a project using the below command.
composer create-project --prefer-dist laravel/laravel datatable-form
Once the project setup is done, let’s open it in the editor. After that, we will do the database configuration setup.
Create and Configure Database
For the database, I will be using MySQL. So, I have created the database
CREATE DATABASE laravel_datatable
After creating the database, you need to configure it in the Laravel project.
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=laravel_datatable
DB_USERNAME={{ DB_USERNAME }}
DB_PASSWORD={{ DB_PASSWORD }}
After configuring database, we need model and migration for data handling.
Create a Model and Migration For Datatable Form Handling
By default, we already have a Model and Migration for the User. Hence, for simplicity, I will be using the same for this project. You may create different Models and Migrations if needed.
I have updated the user migration as shown below.
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->id();
$table->string('name');
$table->string('email')->unique();
$table->string('address');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('users');
}
};
After migration, we need to configure the Factory class belonging to the User model. By using this factory class, I will be adding some dummy records for the user.
How to Create a Zip File of Any Files and Download in Laravel 9
Add Factory Class For Adding Dummy Records
Again, we already have a factory class for the User model. Hence, I will be using the same one. If you needed, you may add another as per the requirement.
<?php
namespace Database\Factories;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
/**
* @extends \Illuminate\Database\Eloquent\Factories\Factory<\App\Models\User>
*/
class UserFactory extends Factory
{
/**
* Define the model's default state.
*
* @return array<string, mixed>
*/
public function definition()
{
return [
'name' => fake()->name(),
'email' => fake()->unique()->safeEmail(),
'address' => fake()->address,
];
}
/**
* Indicate that the model's email address should be unverified.
*
* @return static
*/
public function unverified()
{
return $this->state(fn (array $attributes) => [
'email_verified_at' => null,
]);
}
}
After updating the fields as per the migration in the factory class, we will migrate the table.
php artisan migrate
The above command will migrate the tables as per the migrations schema.
Now, in the next step, we need to create dummy records through factory() class.
php artisan tinker
User::factory()->count(25)->create()
The above command will insert 25 records of users with dummy data.
Now, we are ready with some dummy data to perform datatable form handling. I will be using jQuery Datatable for this entire demo.
How to Use Group Routes For the Same Controller in Laravel 9
Create a Controller
Next, we need a controller from which we will render data to the view and then we can perform Datatable form submission in Laravel 9.
php artisan make:controller UserController
The above command will create the UserController. After creating the controller, just put some snippets in it as shown below.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
class UserController extends Controller
{
/**
* Function : Users Listing
*
* @param Request $request
* @return void
*/
public function index(Request $request) {
$users = User::all();
return view('users', compact('users'));
}
}
In the above snippet, I have just added a function for getting Users data and returning it to the blade file. Next, you need to create a view (blade) on which, you can render the list of Users data.
Create a View For Datatable Form Handling
<!doctype html>
<html lang="en">
<head>
<title>Laravel 9 - DataTable Form Handling</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h3 class="text-center font-weight-bold">Datatable Form Handling in Laravel 9 </h3>
<table class="table mt-2" id="users-table">
<thead>
<th> # </th>
<th> Name </th>
<th> Email </th>
<th> Address </th>
</thead>
<tbody>
@forelse ($users as $key => $user)
<tr>
<input type="hidden" name="userIds[]" value="{{$user->id}}" />
<td>{{$user->id}}</td>
<td>{{$user->name}}</td>
<td>{{$user->email}}</td>
<td>{{$user->address}}</td>
</tr>
@empty
<tr>
<td colspan="4"><span class="text-danger">No data found</span></td>
</tr>
@endforelse
</tbody>
</table>
</div>
<script src="https://code.jquery.com/jquery-3.5.0.js" integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
const table = $('#users-table').DataTable();
});
</script>
</body>
</html>
In the above blade file, I have iterated the users data and initialized datatable for it. Also, I have added a hidden input inside the loop so that we can have the user id of all users.
Now, accordingly, we need to create routes.
How to Clear Application Cache without Command Line in Laravel
Add Route
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\UserController;
Route::get('users', [UserController::class, 'index'])->name('users');
After creating the route, let’s check the application.
Navigate to the specified route and see the result. You will have the datatable with the list of rows.
So, we got data in the datatable. Now, we have to perform form handling for the hidden input as we set for the user id.
So, at the first step, I will wrap the entire table inside a form with an action and add a submit button inside it to submit the user id.
Form Handling in Datatable
After adding the form and submit button, the blade file will become like this.
<!doctype html>
<html lang="en">
<head>
<title>Laravel 9 - DataTable Form Handling</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h3 class="text-center font-weight-bold">Datatable Form Handling in Laravel 9 </h3>
<form action="{{route('users.store')}}" method="POST" id="datatable-form">
@csrf
<button type="submit" class="btn btn-primary float-right my-3">Submit</button>
<table class="table mt-2" id="users-table">
<thead>
<th> # </th>
<th> Name </th>
<th> Email </th>
<th> Address </th>
</thead>
<tbody>
@forelse ($users as $key => $user)
<tr>
<input type="hidden" name="userIds[]" value="{{$user->id}}" />
<td>{{$user->id}}</td>
<td>{{$user->name}}</td>
<td>{{$user->email}}</td>
<td>{{$user->address}}</td>
</tr>
@empty
<tr>
<td colspan="4"><span class="text-danger">No data found</span></td>
</tr>
@endforelse
</tbody>
</table>
</form>
</div>
<script src="https://code.jquery.com/jquery-3.5.0.js" integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
const table = $('#users-table').DataTable();
});
</script>
</body>
</html>
After changing the code, you need to add one more route for the submit handler. So, the routes (web.php) file will become like this.
Route::get('users', [UserController::class, 'index'])->name('users');
Route::post('users', [UserController::class, 'store'])->name('users.store');
Also, you need to update the UserController by adding one submit function as shown below.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\User;
class UserController extends Controller
{
/**
* Function : Users Listing
*
* @param Request $request
* @return void
*/
public function index(Request $request) {
$users = User::all();
return view('users', compact('users'));
}
/**
* Function : Store User
*
* @param Request $request
* @return void
*/
public function store(Request $request) {
dd($request->all());
}
}
Now, just refresh the page to see the updated result.
Here, we have the Submit button inside the form.
Now, let’s try submitting the datatable rows.
On submit, you will get the above response as we added the dump and die function to see the submitted form request. Here, you can notice, we got only 10 rows out of 25. This is the actual problem because we want to submit all rows from the datatable. But it submitted only first page rows which were visible in the DOM.
Now, let’s come to the solution part.
Logout Multiple Auth Session From Other Devices in Laravel 9
Datatable Form Submit Handling By Using jQuery
Now, we will update the code quickly.
- Firstly, we will change the name of the input hidden inside the table and make it unique for every row.
- Then we will create a jQuery form submit event and in that, we will serialize all the inputs available inside the table.
<input type="hidden" name="{{'userId_'.$key}}" value="{{$user->id}}" />
<script type="text/javascript">
$(document).ready(function() {
const table = $('#users-table').DataTable();
$("#datatable-form").submit(function(e) {
// serialize all inputs inside the table
const formData = table.$('input').serializeArray();
// iterate all rows
$.each(formData, function(index, field) {
// append all user id in hidden input
$("#datatable-form").append($(`<input type="hidden" name="${this.name}" value="${this.value}">`));
});
});
});
</script>
So, the overall final snippet became as shown below.
<!doctype html>
<html lang="en">
<head>
<title>Laravel 9 - DataTable Form Handling</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta name="csrf-token" content="{{ csrf_token() }}">
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
<link href="https://cdn.datatables.net/1.10.16/css/jquery.dataTables.min.css" rel="stylesheet">
<link href="https://cdn.datatables.net/1.10.19/css/dataTables.bootstrap4.min.css" rel="stylesheet">
</head>
<body>
<div class="container">
<h3 class="text-center font-weight-bold">Datatable Form Handling in Laravel 9 </h3>
<form action="{{route('users.store')}}" method="POST" id="datatable-form">
@csrf
<button type="submit" class="btn btn-primary float-right my-3">Submit</button>
<table class="table mt-2" id="users-table">
<thead>
<th> # </th>
<th> Name </th>
<th> Email </th>
<th> Address </th>
</thead>
<tbody>
@forelse ($users as $key => $user)
<tr>
<input type="hidden" name="{{'userId_'.$key}}" value="{{$user->id}}" />
<td>{{$user->id}}</td>
<td>{{$user->name}}</td>
<td>{{$user->email}}</td>
<td>{{$user->address}}</td>
</tr>
@empty
<tr>
<td colspan="4"><span class="text-danger">No data found</span></td>
</tr>
@endforelse
</tbody>
</table>
</form>
</div>
<script src="https://code.jquery.com/jquery-3.5.0.js" integrity="sha256-r/AaFHrszJtwpe+tHyNi/XCfMxYpbsRg2Uqn0x3s2zc=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js" integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1" crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js" integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM" crossorigin="anonymous"></script>
<script src="https://cdn.datatables.net/1.10.16/js/jquery.dataTables.min.js"></script>
<script src="https://cdn.datatables.net/1.10.19/js/dataTables.bootstrap4.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
const table = $('#users-table').DataTable();
$("#datatable-form").submit(function(e) {
// serialize all inputs inside the table
const formData = table.$('input').serializeArray();
// iterate all rows
$.each(formData, function(index, field) {
// append all user id in hidden input
$("#datatable-form").append($(`<input type="hidden" name="${this.name}" value="${this.value}">`));
});
});
});
</script>
</body>
</html>
Now, just refresh the page and see the updated results.
Here, in the controller, you can see all the rows (25 counts) are submitted with the index. So, from here, you can easily iterate these rows to save.
For that, we can pass one more hidden input for the number of rows, and based on that count, we can make a loop iteration to extract all the inputs in the controller.
So, let’s update the script part quickly.
<script type="text/javascript">
$(document).ready(function() {
const table = $('#users-table').DataTable();
const countRows = [];
$("#datatable-form").submit(function(e) {
// serialize all inputs inside the table
const formData = table.$('input').serializeArray();
// iterate all rows
$.each(formData, function(index, field) {
// pushing total counts of the user id input
if ((field.name).indexOf('userId_') !== -1) {
countRows.push(index);
}
// append all user id in hidden input
$("#datatable-form").append($(`<input type="hidden" name="${this.name}" value="${this.value}">`));
});
// append count of rows
$("#datatable-form").append($(`<input type="hidden" name="rowsCount" value="${countRows.length}">`));
});
});
</script>
In the above script, we appended one more hidden input for the count of input name having userId. So, in the request inside the controller, we will get one additional field.
Now, on the basis of this count field, we can map these rows in the form of an array. So that we can store the data in the table or can perform other actions as well.
Map Datatable Form Submitted Rows
So, let’s do some updates in the store() function inside the UserController.
/**
* Function : Store User
*
* @param Request $request
* @return void
*/
public function store(Request $request) {
$formRequests = [];
if ($request->rowsCount > 0) {
for ($i = 0; $i < $request->rowsCount; $i++) {
$formRequests[] = [
'user_id' => $request->input('userId_'.$i),
];
}
}
dd($formRequests);
}
Now, refresh the page to see the final result.
Now, we simplified the request data in the form of an array so that we can insert it in the database table.
Conclusion
Finally, we achieved the result of datatable form submission in Laravel 9. We have seen step by step, how datatable renders only the visible rows, and on submitting the request the visible rows are being submitted. But, we achieved all rows submission by serializing all the inputs from that particular table and appended in the form. So, on submit request, we got all the rows from that datatable.
That’s it for this post. I hope you will find helpful to this post.
Leave a Reply