← Kembali ke kursus
Pelajaran kursus · JavaScript
Pelajaran 49

Proyek: Todo List

CRUD lengkap dengan localStorage dan event delegation.

Pahami konsepnya

Proyek ini menggabungkan hampir semua yang dipelajari di bagian browser: selektor DOM, createElement, event listener, form handling, localStorage, dan event delegation. Hasilnya aplikasi Todo List yang bisa menambah, menandai selesai, menghapus, dan menyimpan data yang bertahan setelah reload.

Struktur: (1) form untuk input tugas baru; (2) ul untuk daftar; (3) localStorage untuk persist; (4) event delegation di ul untuk tombol per item. Data disimpan sebagai array objek: [{ teks, selesai }].

Kerangka sudah disiapkan — lengkapi bagian bertanda TODO sampai aplikasi berjalan penuh.

Coba contoh kode

<!doctype html>
<html>
<head>
  <style>
    body { font-family: sans-serif; max-width: 400px; margin: 40px auto; }
    .selesai { text-decoration: line-through; opacity: 0.5; }
    li { display: flex; align-items: center; gap: 8px; padding: 4px 0; }
  </style>
</head>
<body>
  <h1>Todo List</h1>
  <form id="form">
    <input id="input" placeholder="Tugas baru..." required>
    <button>Tambah</button>
  </form>
  <ul id="daftar"></ul>

  <script>
    const form = document.getElementById("form");
    const input = document.getElementById("input");
    const daftar = document.getElementById("daftar");

    let tugas = JSON.parse(localStorage.getItem("tugas") || "[]");

    function simpan() {
      localStorage.setItem("tugas", JSON.stringify(tugas));
    }

    function render() {
      daftar.innerHTML = "";
      tugas.forEach((t) => {
        const li = document.createElement("li");
        const centang = document.createElement("input");
        centang.type = "checkbox";
        centang.checked = t.selesai;
        const teks = document.createElement("span");
        teks.classList.toggle("selesai", t.selesai);
        teks.textContent = t.teks;
        const hapus = document.createElement("button");
        hapus.type = "button";
        hapus.textContent = "Hapus";
        hapus.style.marginLeft = "auto";
        li.append(centang, teks, hapus);
        daftar.appendChild(li);
      });
    }

    form.addEventListener("submit", (e) => {
      e.preventDefault();
      tugas.push({ teks: input.value, selesai: false });
      input.value = "";
      simpan(); render();
    });

    daftar.addEventListener("click", (e) => {
      const idx = [...daftar.children].indexOf(e.target.closest("li"));
      if (idx < 0) return;
      if (e.target.type === "checkbox") tugas[idx].selesai = !tugas[idx].selesai;
      else if (e.target.textContent === "Hapus") tugas.splice(idx, 1);
      simpan(); render();
    });

    render();
  </script>
</body>
</html>

Aplikasi penuh: form menambah, checkbox menandai selesai, tombol menghapus, localStorage menyimpan. Event delegation di ul menangani semua interaksi item dengan satu listener. Latihan editor meminta fungsi penambah tugas yang mengubah array dan mengembalikan jumlah tugas.

Latihan singkat

Uji: fungsi tambahTugas(daftar, teks) menambah {teks, selesai:false} lalu kembalikan panjang daftar.