Daftar tugas, baris tabel, kartu produk — hampir semua halaman web dibangun dari perulangan data. Tidak heran bila @foreach menjadi directive yang paling sering kita tulis di Blade. Larinya pun sederhana: blok di dalam @foreach diulang sekali untuk setiap item, persis foreach PHP. Yang membuat Blade istimewa adalah variabel $loop yang tersedia otomatis di setiap perulangan — tanpa kita menghitung counter manual. Chapter ini menguji @foreach, $loop, @forelse, @for, dan @while dengan output nyata dari setiap skenario.
Perulangan Koleksi dengan @foreach #
Bentuk dasarnya mengambil satu item dari koleksi lalu menampilkannya di dalam blok. Controller mengirim array tugas; view mengulang dan menampilkan tiap judul:
<ul>
@foreach ($tugas as $judul)
<li>{{ $judul }}</li>
@endforeach
</ul>Untuk associative array atau model Eloquent, bentuk @foreach ($tugas as $kunci => $nilai) juga tersedia seperti pada PHP biasa. Collection Laravel — hasil Task::all() misalnya — diperlakukan sama persis seperti array, jadi satu directive ini menutup hampir semua kebutuhan perulangan tampilan.
Variabel $loop #
Di dalam @foreach dan @forelse, Blade menyediakan objek $loop yang memuat posisi serta kondisi iterasi berjalan. Propertinya yang paling sering dipakai:
| Properti | Arti |
|---|---|
$loop->index | Indeks iterasi berjalan, mulai dari 0 |
$loop->iteration | Nomor iterasi berjalan, mulai dari 1 |
$loop->remaining | Jumlah item tersisa setelah iterasi ini |
$loop->count | Total item dalam koleksi |
$loop->first | true bila iterasi pertama |
$loop->last | true bila iterasi terakhir |
$loop->depth | Kedalaman nested loop, mulai dari 1 |
$loop->parent | Objek $loop dari perulangan induk |
View daftar-tugas.blade.php memakai lima properti pertama sekaligus:
<ul>
@foreach ($tugas as $judul)
<li>{{ $loop->iteration }}. {{ $judul }} — index {{ $loop->index }}, sisa {{ $loop->remaining }}, total {{ $loop->count }}{{ $loop->first ? ' [pertama]' : '' }}{{ $loop->last ? ' [terakhir]' : '' }}</li>
@endforeach
</ul>Output yang Dihasilkan untuk tiga tugas:
<ul>
<li>1. Belajar Blade — index 0, sisa 2, total 3 [pertama]</li>
<li>2. Uji coba view — index 1, sisa 1, total 3</li>
<li>3. Tulis migration — index 2, sisa 0, total 3 [terakhir]</li>
</ul>Perhatikan pasangan iteration dan index: yang pertama mulai dari 1 untuk nomor urut tampilan, yang kedua mulai dari 0 sesuai kebiasaan indeks PHP. Kedua konvensi ini sering tertukar, padahal keduanya melayani kebutuhan berbeda. Tanpa $loop, kita terpaksa memelihara counter manual seperti @php $i = 1; @endphp lalu menaikkannya di akhir blok — kode yang mudah lupa ditulis dan rawan meleset saat ada @continue di tengah perulangan.
Perulangan Bersarang dan $loop->parent #
Saat satu @foreach berada di dalam @foreach lain, variabel $loop milik perulangan terdalam otomatis menimpa yang luar. Untuk mengakses $loop induk, gunakan $loop->parent. View kategori-tugas.blade.php mengelompokkan tugas per kategori lalu memberi nomor ganda:
@foreach ($kategori as $nama => $daftar)
<h2>{{ $nama }}</h2>
<ul>
@foreach ($daftar as $judul)
<li>grup {{ $loop->parent->iteration }}. item {{ $loop->iteration }} — {{ $judul }}</li>
@endforeach
</ul>
@endforeachOutput yang Dihasilkan:
<h2>Rumah Tangga</h2>
<ul>
<li>grup 1. item 1 — Cuci baju</li>
<li>grup 1. item 2 — Beli sayur</li>
</ul>
<h2>Belajar</h2>
<ul>
<li>grup 2. item 1 — Baca dokumentasi</li>
</ul>Nomor grup berasal dari perulangan luar melalui $loop->parent->iteration, sedangkan nomor item dari perulangan dalam. Untuk kedalaman lebih dari dua tingkat, $loop->parent->parent menulusuri ke atas sesuai jumlah tingkatnya.
@forelse untuk Kondisi Kosong #
Masalah klasik @foreach: koleksi kosong menghasilkan elemen pembungkus kosong — tabel tanpa baris, daftar tanpa isi. Directive @forelse memecahnya dengan blok @empty yang hanya dirender saat koleksi kosong:
<table>
<tr><th>Judul</th><th>Status</th></tr>
@forelse ($tugas as $t)
<tr><td>{{ $t['judul'] }}</td><td>{{ $t['status'] }}</td></tr>
@empty
<tr><td colspan="2">Tidak ada tugas yang cocok dengan filter.</td></tr>
@endforelse
</table>Output untuk koleksi terisi dan koleksi kosong:
<table>
<tr><th>Judul</th><th>Status</th></tr>
<tr><td>Belajar Blade</td><td>selesai</td></tr>
<tr><td>Tulis migration</td><td>proses</td></tr>
</table>
<table>
<tr><th>Judul</th><th>Status</th></tr>
<tr><td colspan="2">Tidak ada tugas yang cocok dengan filter.</td></tr>
</table>Variabel $loop juga tersedia di dalam @forelse, jadi semua properti pada tabel sebelumnya tetap berlaku.
@for dan @while untuk Perulangan Numerik #
Bila yang diulang bukan koleksi melainkan rentang angka — nomor halaman misalnya — @for lebih tepat:
<nav>
@for ($i = 1; $i <= 3; $i++)
<a href="?halaman={{ $i }}">H{{ $i }}</a>
@endfor
</nav>Sementara @while mengulang selama kondisi benar — cocok untuk pagination yang nomornya dihitung dari total data:
@php $halaman = 4; @endphp
<div>
@while ($halaman <= 6)
<a href="?halaman={{ $halaman }}">H{{ $halaman }}</a>
@php $halaman++; @endphp
@endwhile
</div>Output yang Dihasilkan:
<nav>
<a href="?halaman=1">H1</a>
<a href="?halaman=2">H2</a>
<a href="?halaman=3">H3</a>
</nav>
<div>
<a href="?halaman=4">H4</a>
<a href="?halaman=5">H5</a>
<a href="?halaman=6">H6</a>
</div>Menghentikan dan Melewati Iterasi #
Dua directive khusus mengendalikan perulangan dari dalam. @continue melompati iterasi berjalan, @break menghentikan seluruh perulangan — keduanya menerima kondisi sebagai argumen. View filter-tugas.blade.php melewati judul berstatus draf lalu berhenti setelah dua item:
<ul>
@foreach ($tugas as $judul)
@continue($judul === 'Draf')
<li>{{ $judul }}</li>
@endforeach
</ul>
@php $maks = 2; @endphp
<span>Dua item pertama:</span>
@foreach ($tugas as $judul)
@if ($loop->iteration > $maks)
@break
@endif
<b>{{ $judul }}</b>
@endforeachOutput yang Dihasilkan untuk ['Belajar Blade', 'Draf', 'Uji coba view', 'Tulis migration']:
<ul>
<li>Belajar Blade</li>
<li>Uji coba view</li>
<li>Tulis migration</li>
</ul>
<span>Dua item pertama:</span>
<b>Belajar Blade</b>
<b>Draf</b>Item Draf tidak pernah menjadi <li> di daftar pertama, dan daftar kedua berhenti tepat setelah dua item.
Perulangan menuntaskan kosakata dinamis satu halaman. Berikutnya kita angkat kerja yang membuat puluhan halaman konsisten: mewariskan satu layout induk kepada semua halaman anak lewat @extends — materi chapter Template Inheritance.