Server-Side DataTables Rendering in Laravel

Published: (May 10, 2026 at 06:54 PM EDT)
2 min read
Source: Dev.to

Source: Dev.to


⚠️ Collection Error: Content refinement error: Error: 429 “you (bkperio) have reached your weekly usage limit, upgrade for higher limits: https://ollama.com/upgrade (ref: 82afb66f-8455-4771-8df0-cea9051e57a2)”


Aside from doing indexes, and use join() instead of with(). This example uses the DataTables library.

Route::post(‘/data’, [App\Http\Controllers\MyController::class, ‘datatable’])->name(‘mydata.datatable’);

Date input, datatable, and button.

Start Date


End Date


Show


    
        INVOICE
        AMOUNT
    

$(‘#btnTampilkan’).on(‘click’, function() { _loadMyData(); });

let table; function _loadMyData() { var start = $(‘#start_date’).val(); var end = $(‘#end_date’).val(); if (table) table.destroy(); if (!start || !end) return Swal.fire(‘Warning’, ‘Start & End date is required!’, ‘warning’); table = $(‘#tableMyData’).DataTable({ processing: true, autoWidth: false, serverSide: true, pagingType: ‘full_numbers’, lengthMenu: [[10, 20, 50, 100], [10, 20, 50, 100]], pageLength: 10, destroy: true, ajax: { url: ”{{ route(‘mydata.datatable’) }}”, type: ‘POST’, data: { start_date: start, end_date: end, _token: ”{{ csrf_token() }}” } }, language: { emptyTable: “No data found” }, order: [[1, ‘desc’]], columnDefs: [ { orderable: false, targets: 0, width: ‘3%’ }, ], columns: [ { data: null, render: (data) => “ }, { data: ‘invoice’ }, { data: ‘amount’ }, ], // search delay initComplete() { const api = this.api(); let typingTimer; $(‘#tableMyData_filter input’).off().on(‘keyup’, function (e) { clearTimeout(typingTimer); const value = this.value; if (e.which === 13) { api.search(value).draw(); } else { typingTimer = setTimeout(() => api.search(value).draw(), 500); } }); } }); }

use Illuminate\Http\Request;

public function datatable(Request $request) { $query = … ->whereBetween(‘order_date’, [$request->start, $request->end]);

$maxLimit = 100000;
$columns = [null, 'invoice', 'amount'];

$recordsTotal = min((clone $query)->count(), $maxLimit);
// SEARCH
if ($search = $request->input('search.value')) {
    $normalized = str_replace(['.', ','], '', $search);
    $query->where(function($q) use ($search, $normalized) {
        $q->where('invoice', 'LIKE', "%{$search}%")
          ->orWhere('amount', 'LIKE', "%{$search}%");
    });
}

$recordsFiltered = min((clone $query)->count(), $maxLimit);

// ORDERING
$order = $request->input('order', []);
if ($order && ($col = $columns[$order[0]['column']] ?? null)) {
    $query->orderBy($col, $order[0]['dir'] ?? 'ASC');
} else {
    $query->orderBy('order_date', 'ASC');
}

// PAGINATION
$start = $request->input('start');
$results = $start >= $maxLimit
    ? collect()
    : $query->offset($start)
            ->limit(min($request->input('length'), $maxLimit - $start))
            ->get();

return response()->json([
    'draw' => intval($request->draw),
    'recordsTotal' => $recordsTotal,
    'recordsFiltered' => $recordsFiltered,
    'data' => $results->map(fn($r) => [
        'invoice' => $r->invoice,
        'amount' => $r->amount,
    ])
]);

}

Need help building your app? I’m available for freelance web & Android development — raflizocky.netlify.app ☕ Support my writing: paypal.me/raflizocky · saweria.co/raflizocky

0 views
Back to Blog

Related posts

Read more »