Proyek Pertama: To-Do List
Saatnya menggabungkan HTML, CSS, dan JavaScript jadi satu — proyek nyata pertama yang benar-benar bisa kamu pakai sehari-hari.
Coba Dulu Hasil Akhirnya
Sebelum membahas kodenya, coba dulu aplikasi yang akan kamu bangun. Tambahkan beberapa tugas, centang yang sudah selesai, lalu hapus salah satunya.
Langkah 1: Struktur HTML
1Mulai dengan kerangka HTML: kolom input, tombol tambah, dan list kosong yang akan diisi oleh JavaScript.
<div class="todo-app">
<div class="todo-input-row">
<input type="text" id="todoInput" placeholder="Tulis tugas baru...">
<button onclick="tambahTugas()">Tambah</button>
</div>
<ul class="todo-list" id="todoList"></ul>
</div>
Perhatikan: <ul id="todoList"> sengaja dikosongkan di HTML — isinya akan diisi secara dinamis oleh JavaScript setiap kali daftar tugas berubah.
Langkah 2: Styling dengan CSS
2Beri jarak dan tampilan dasar. Ini menggunakan konsep box model dan flexbox yang sudah dipelajari di Modul 03.
.todo-input-row {
display: flex;
gap: 8px;
margin-bottom: 16px;
}
.todo-list li {
display: flex;
align-items: center;
gap: 10px;
padding: 10px 4px;
border-bottom: 1px solid #ddd;
}
.todo-list li.done span {
text-decoration: line-through;
color: gray;
}
Langkah 3: Logika JavaScript
3Simpan daftar tugas sebagai array of objects — setiap tugas punya teks dan status selesai/belum.
let daftarTugas = [];
function tambahTugas() {
const input = document.getElementById("todoInput");
const teks = input.value.trim();
if (teks === "") return; // jangan tambah tugas kosong
daftarTugas.push({ teks: teks, selesai: false });
input.value = "";
renderTugas();
}
4Fungsi renderTugas() bertugas "menggambar ulang" seluruh list setiap kali ada perubahan — ini pola yang sangat umum dipakai di JavaScript.
function renderTugas() {
const list = document.getElementById("todoList");
list.innerHTML = ""; // kosongkan dulu sebelum digambar ulang
daftarTugas.forEach((tugas, index) => {
const li = document.createElement("li");
if (tugas.selesai) li.classList.add("done");
li.innerHTML = `
<input type="checkbox" onchange="toggleTugas(${index})">
<span>${tugas.teks}</span>
<button onclick="hapusTugas(${index})">Hapus</button>
`;
list.appendChild(li);
});
}
5Terakhir, fungsi untuk mengubah status selesai dan menghapus tugas:
function toggleTugas(index) {
daftarTugas[index].selesai = !daftarTugas[index].selesai;
renderTugas();
}
function hapusTugas(index) {
daftarTugas.splice(index, 1); // hapus 1 item di posisi `index`
renderTugas();
}
Langkah 4: Menyimpan Data dengan Local Storage
Masalah dengan kode di atas: kalau halaman di-refresh, semua tugas hilang karena hanya tersimpan di memori sementara (variabel JavaScript). Local storage adalah cara browser menyimpan data secara permanen di perangkat pengguna, sampai dihapus secara manual.
// Menyimpan data ke local storage (ubah jadi teks dulu dengan JSON.stringify)
function simpanData() {
localStorage.setItem("tugas", JSON.stringify(daftarTugas));
}
// Mengambil data saat halaman dimuat
function muatData() {
const data = localStorage.getItem("tugas");
if (data) {
daftarTugas = JSON.parse(data);
}
}
// Panggil simpanData() di akhir setiap fungsi tambah/toggle/hapus
// Panggil muatData() sekali saat halaman pertama kali dibuka
Local storage hanya bisa menyimpan teks (string), bukan array atau object langsung. JSON.stringify() mengubah data JavaScript jadi teks, dan JSON.parse() mengubahnya kembali jadi data JavaScript saat diambil.
Langkah 5: Debugging — Saat Kode Tidak Berjalan
Hampir pasti kode pertamamu tidak akan langsung berjalan sempurna. Ini normal — bahkan programmer berpengalaman mengalaminya setiap hari. Beberapa kebiasaan debugging dasar:
- Buka Console di browser (klik kanan → Inspect → tab Console) — error JavaScript akan muncul di sana dengan pesan yang biasanya menunjukkan baris mana yang bermasalah.
- Gunakan console.log() di banyak tempat untuk memeriksa nilai variabel pada titik tertentu dalam kode — ini teknik debugging paling dasar dan paling sering dipakai.
- Baca pesan error dari bawah ke atas — baris paling atas biasanya menunjukkan akar masalah sebenarnya.
- Cek typo nama variabel/fungsi — JavaScript sensitif terhadap huruf besar/kecil (
tambahTugasberbeda daritambahtugas).
Uncaught ReferenceError: x is not defined — biasanya berarti kamu memanggil variabel/fungsi yang belum dideklarasikan, atau ada typo pada namanya.
Latihan Pengembangan
Setelah memahami kode di atas, coba kembangkan sendiri kemampuan to-do list ini:
- Tambahkan fitur "Hapus Semua Tugas yang Selesai"
- Tambahkan penghitung jumlah tugas yang belum selesai
- Tambahkan local storage agar data tidak hilang saat refresh (lihat Langkah 4)
Latihan Pemahaman
Soal 1: Mengapa fungsi renderTugas() perlu mengosongkan list (innerHTML = "") di awal?
Soal 2: Apa fungsi dari JSON.stringify() saat menyimpan data ke local storage?
Rangkuman Modul Ini
- Proyek nyata menggabungkan HTML (struktur), CSS (tampilan), dan JavaScript (logika) sekaligus.
- Pola "render ulang" (render function) adalah cara umum memperbarui tampilan berdasarkan data.
- Local storage memungkinkan data tersimpan permanen di browser pengguna.
- Debugging adalah bagian normal dari proses ngoding — console.log() adalah teman terbaikmu.
Selamat — kamu baru menyelesaikan proyek pertamamu! Modul terakhir akan membahas ke mana arah belajarmu selanjutnya setelah fondasi ini selesai.