Pada artikel ini saya akan share cara membuat datatable yang responsive dengan jQuery untuk mobile, tablet, web dengan laravel 12. Yang pertama jangan lupa install base framework laravel 12, ini linknya https://laravel.com/docs/12.x/installation.
Jika sudah install laravel, untuk percobaan awal, ubah di file welcome page, tambah dengan table responsive yang sudah saya siapkan, dari table ini point pentingnya ada di id="newsTable" untuk di panggila ke kode jQuerynya
jika sudah tambah kode jQuery yang sudah saya siapkan yang kan menset dataTable jQuery agar bisa responsive saat mode web, tablet, mobile
<div class="table-responsive">
<table id="newsTable"
class="table table-selectable card-table table-vcenter text-nowrap datatable">
<thead>
<tr>
<th class="w-1"></th>
<th class="w-1">No.</th>
<th>Title</th>
<th>Slug</th>
<th>Content</th>
<th>Author</th>
<th>Image</th>
<th>Published At</th>
<th>Excerpt</th>
<th>Code Snippet</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
@foreach ($news as $loopIndex => $item)
<tr>
<td></td>
<td><span
class="text-secondary">{{ str_pad($loopIndex + 1, 3, '0', STR_PAD_LEFT) }}</span>
</td>
<td class="text-wrap text-justify">{{ $item->title }}</td>
<td class="text-wrap text-justify">{{ $item->slug }}</td>
<td class="text-wrap text-justify">{{ Str::limit($item->content, 100) }}</td>
<td>{{ $item->author }}</td>
<td>
@if ($item->image)
<img src="{{ asset('storage/' . $item->image) }}" alt="image"
style="max-width:80px; max-height:60px;">
@else
-
@endif
</td>
<td>{{ $item->published_at ? $item->published_at->format('d-m-Y H:i') : '-' }}
</td>
<td class="text-wrap text-justify">{{ $item->excerpt }}</td>
<td style="max-width:400px;">
@if ($item->codeSnippets && $item->codeSnippets->count() > 0)
<div style="margin-bottom:0.5rem;">
<span class="badge"
style="background-color:#3b82f6;color:white;padding:0.35rem 0.6rem;border-radius:6px;font-size:0.8rem;">
📝 {{ $item->codeSnippets->count() }}
snippet{{ $item->codeSnippets->count() > 1 ? 's' : '' }}
</span>
</div>
@foreach ($item->codeSnippets as $index => $snippet)
<div
style="margin-bottom:1rem;border-left:3px solid #3b82f6;padding-left:0.75rem;">
@if ($snippet->title)
<div
style="font-weight:600;color:#1e293b;margin-bottom:0.25rem;font-size:0.85rem;">
{{ $snippet->title }}
</div>
@else
<div
style="font-weight:600;color:#64748b;margin-bottom:0.25rem;font-size:0.85rem;">
Snippet #{{ $index + 1 }}
</div>
@endif
@if ($snippet->language)
<span
style="background:#f1f5f9;color:#475569;padding:0.15rem 0.4rem;border-radius:4px;font-size:0.75rem;margin-bottom:0.5rem;display:inline-block;">
{{ $snippet->language }}
</span>
@endif
<pre
style="background:#f8fafc;border:1px solid #e2e8f0;padding:0.5rem;border-radius:6px;overflow:auto;max-height:150px;margin:0.5rem 0 0 0;"><code style="font-size:0.75rem;color:#334155;">{{ Str::limit($snippet->code, 200) }}</code></pre>
</div>
@endforeach
@else
<span style="color:#94a3b8;font-weight:500;">-</span>
@endif
</td>
<td class="text-end">
<span class="dropdown">
<button class="btn dropdown-toggle align-text-top"
data-bs-boundary="viewport"
data-bs-toggle="dropdown">Actions</button>
<div class="dropdown-menu dropdown-menu-end">
<button type="button" class="dropdown-item btn-edit-news"
data-bs-toggle="modal" data-bs-target="#modal-edit-news"
data-uuid="{{ $item->uuid }}">Edit</button>
<form method="POST"
action="{{ route('news.destroy', $item->uuid) }}"
style="display: inline;">
@csrf
@method('DELETE')
<button type="submit" class="dropdown-item text-danger"
onclick="return confirm('Yakin ingin menghapus data ini?')">Delete</button>
</form>
</div>
</span>
</td>
</tr>
@endforeach
</tbody>
</table>
</div>
<script>
$(document).ready(function() {
$('#newsTable').DataTable({
responsive: {
breakpoints: [{
name: 'bigdesktop',
width: Infinity
},
{
name: 'meddesktop',
width: 1480
},
{
name: 'smalldesktop',
width: 1400
},
{
name: 'medium',
width: 1024
},
{
name: 'tabletl',
width: 768
},
{
name: 'btwtabletmobile',
width: 480
},
{
name: 'mobile',
width: 320
}
]
},
columnDefs: [{
className: 'dtr-control',
orderable: false,
targets: 0,
responsivePriority: 1
},
{
targets: [1, 2], // No, Title, Slug - always visible
responsivePriority: 1
},
{
targets: [3], // Spacer for better responsiveness
responsivePriority: 8
},
{
targets: [4], // Content
className: 'text-wrap text-justify',
responsivePriority: 10
},
{
targets: [5, 6, 7], // Author, Image, Published At
responsivePriority: 1
},
{
targets: [8], // Excerpt
responsivePriority: 10,
className: 'text-wrap text-justify'
},
{
targets: [9], // Code Snippet
responsivePriority: 15,
orderable: false
},
{
targets: [10], // Actions - always visible
responsivePriority: 10,
orderable: false
}
],
order: [
[1, 'asc']
],
pageLength: 10,
language: {
search: "Search:",
lengthMenu: "Show _MENU_ entries",
info: "Showing _START_ to _END_ of _TOTAL_ entries",
infoEmpty: "No entries found",
infoFiltered: "(filtered from _MAX_ total entries)",
paginate: {
first: "First",
last: "Last",
next: "Next",
previous: "Previous"
}
}
});
});
</script>
// Route memanggil ke controller news
Route::get('/news', [NewsController::class, 'index'])->name('news.index');
// Controller memanggil data news dari database
public function index()
{
$news = News::with(['images', 'codeSnippets'])->get();
return view('welcome', compact('news'));
}