Form yang menghapus seluruh isian setiap kali validasi gagal adalah penyiksaan kecil bagi pengguna: bayangkan mengetik ulang bio panjang hanya karena kolom email terlewat. Laravel mencegahnya dengan mekanisme old input — input yang di-flash ke session saat redirect balik, lalu disajikan kembali ke view lewat helper old(). Mekanismenya sederhana untuk input teks, tetapi butuh pola tersendiri untuk select, radio, dan checkbox yang state-nya ditentukan atribut selected/checked. Chapter ini melengkapi form registrasi chapter sebelumnya agar semua jenis input pulih utuh setelah kegagalan validasi.

withInput() dan Siklus Flash #

Redirect dari kegagalan validasi Laravel otomatis membawa input lama. Untuk redirect manual, kita memanggilnya eksplisit:

php
return redirect()
    ->route('register.create')
    ->withInput($request->except('password', 'password_confirmation'));

Argumen except() itu penting: field sensitif seperti password sebaiknya tidak di-flash ke session. Flash data ini hidup tepat satu request berikutnya — kita buktikan lewat dua GET berturut-turut setelah POST yang gagal:

Output yang Dihasilkan:

text
GET ke-1 (request tepat setelah POST):
{"old_nama":"Budi","old_kota":"Bandung","old_default":"tidak-diisi"}

GET ke-2 (flash sudah hangus):
{"old_nama":null,"old_kota":null,"old_default":"tidak-diisi"}

Request pertama masih menemukan nama dan kota dari POST tadi; request kedua sudah tidak menemukan apa pun karena flash data hangus terpakai. Perilaku ini menjelaskan kenapa old input aman dipakai — data tidak menetap di session selamanya.

old() untuk Teks dan Textarea #

Helper old('field') mengambil nilai flash; argumen kedua yang opsional menjadi nilai bawaan saat tidak ada:

blade
<input id="nama" type="text" name="nama" value="{{ old('nama') }}">
<input id="telepon" type="text" name="telepon" value="{{ old('telepon', '08') }}">

<textarea id="bio" name="bio">{{ old('bio') }}</textarea>

Untuk textarea, old() ditulis di antara tag pembuka dan penutup — bukan di atribut value yang tidak dimiliki textarea. Nilai default '08' pada telepon tampil saat form pertama dibuka maupun saat flash sudah hangus.

State selected dan checked #

Elemen select, radio, dan checkbox tidak memakai value untuk menandai pilihan — mereka butuh atribut selected atau checked. Blade menyediakan directive @selected dan @checked yang menerima boolean:

blade
<select id="kota" name="kota">
    <option value="">-- pilih kota --</option>
    @foreach (['Jakarta', 'Bandung', 'Surabaya'] as $k)
        <option value="{{ $k }}" @selected(old('kota') === $k)>{{ $k }}</option>
    @endforeach
</select>

<label>
    <input type="radio" name="jenis_kelamin" value="L"
           @checked(old('jenis_kelamin') === 'L')> Laki-laki
</label>
<label>
    <input type="radio" name="jenis_kelamin" value="P"
           @checked(old('jenis_kelamin') === 'P')> Perempuan
</label>

@foreach (['Membaca', 'Olahraga', 'Musik'] as $h)
    <label>
        <input type="checkbox" name="hobi[]" value="{{ $h }}"
               @checked(in_array($h, old('hobi', [])))> {{ $h }}
    </label>
@endforeach

Perbandingan old('kota') === $k mengevaluasi benar hanya untuk opsi yang dulu dipilih. Checkbox adalah kasus istimewa: old('hobi', []) wajib diberi default array kosong karena in_array() akan error bila old input berbentuk null — dan input hobi[] dikirim sebagai array.

Form Lengkap Setelah Kegagalan #

Kita rakit bukti utuh: POST dengan data hampir valid (hanya konfirmasi password yang salah), lalu GET halaman form. Inilah cuplikan hasil render nyatanya:

Output yang Dihasilkan:

text
<form method="POST" action="http://localhost:8000/register">
        <label for="nama">Nama</label>
        <input id="nama" type="text" name="nama" value="Budi"
               class="">

        <label for="email">Email</label>
        <input id="email" type="email" name="email" value="[email protected]"
               class="">

        <label for="password">Password</label>
        <input id="password" type="password" name="password"
               class=" border-red-500 ">

        <label for="password_confirmation">Ulangi Password</label>
        <input id="password_confirmation" type="password" name="password_confirmation">

        <label>Jenis Kelamin</label>
        <label>
            <input type="radio" name="jenis_kelamin" value="L"
                   checked> Laki-laki
        </label>

Input teks kembali terisi value="Budi" dan value="[email protected]"; radio Laki-laki membawa checked. Lanjutan render menunjukkan select dan checkbox:

Output yang Dihasilkan:

text
        <label for="kota">Kota</label>
        <select id="kota" name="kota">
            <option value="">-- pilih kota --</option>
                            <option value="Jakarta" >Jakarta</option>
                            <option value="Bandung" selected>Bandung</option>

Opsi Bandung tercetak dengan atribut selected, dan checkbox hobi[] bernilai Membaca membawa checked. Field password sengaja tetap kosong — sesuai perilaku bawaan validasi yang tidak meng-flash password — sementara class border-red-500 menandainya sebagai satu-satunya field yang bermasalah.

old() di Luar Blade #

Di konteks non-view — middleware, controller, atau command yang menangani request — nilai yang sama bisa diambil lewat request()->old():

php
$namaLama = request()->old('nama');
$telepon = request()->old('telepon', 'tidak-diisi');

Sintaks ini identik dengan helper old() karena keduanya berujung pada session key _old_input.

Dengan old input dan tampilan error yang bekerja sama, halaman form kita kini menghormati usaha pengguna: salah satu field salah, semuanya tinggal diperbaiki, bukan ditulis ulang. Pola yang tersisa untuk melengkapi gambar validasi adalah data yang kompleks — array bersarang dalam dan request JSON dari API — yang kita tangani di chapter penutup section ini. Untuk pendalaman, rujuk dokumentasi Requests — Old Input .