Episode ini membahas cara halaman merespons pengguna: mendaftar event dengan addEventListener, membaca event object, memahami perambatan event (bubbling), serta pola delegasi event yang efisien untuk elemen yang dibuat secara dinamis.

Di episode 13 kalian bisa memanipulasi DOM secara pasif — kalian mengubah halaman, tapi halaman belum bisa merespons kalian. Event menjembatani kesenjangan itu: saat pengguna mengklik, mengetik, atau menekan tombol, browser membangkitkan event yang bisa ditangkap oleh JavaScript. Inilah inti interaktivitas web.
Episode 14 membahas event handling dari dasar: mendaftarkan handler dengan addEventListener, membaca data dari event object, memahami dua konsep yang menentukan alur event — perambatan dan preventDefault — serta delegasi event, pola yang membuat aplikasi dengan banyak elemen dinamis tetap efisien dan mudah dirawat.
Setelah episode ini, kalian bisa membangun halaman yang benar-benar hidup: klik, input, dan keyboard semuanya merespons dengan benar.
addEventListener mendaftarkan fungsi yang dipanggil saat event terjadi. Bentuknya selalu element.addEventListener("nama-event", handler):
const tombol = document.querySelector("#tombol");
tombol.addEventListener("click", () => {
console.log("Tombol diklik!");
});tombol.addEventListener("click", () => {...}) memanggil callback setiap kali tombol diklik. Handler ini tidak menimpa handler lain — addEventListener bisa mendaftar berkali-kali pada elemen yang sama untuk event yang sama. Inilah alasan addEventListener lebih disukai daripada properti onclick lama.
Handler menerima satu argumen: event object yang berisi data tentang kejadian tersebut — elemen yang terkena, tombol mana, dan posisi kursor:
const kartu = document.querySelector("#kartu");
kartu.addEventListener("click", (event) => {
console.log("Elemen target:", event.target);
console.log("Elemen handler:", event.currentTarget);
console.log("Koordinat:", event.clientX, event.clientY);
});(event) => menerima event object. event.target adalah elemen yang benar-benar diklik, sedangkan event.currentTarget adalah elemen tempat handler dipasang — keduanya berbeda jika ada elemen di dalam elemen. event.clientX dan clientY memberi posisi kursor relatif terhadap viewport.
Tiga event yang paling sering dipakai: click untuk elemen yang bisa diklik, input untuk kolom teks, dan keydown untuk keyboard:
const input = document.querySelector("#nama");
input.addEventListener("input", () => {
console.log("Isi sekarang:", input.value);
});
input.addEventListener("keydown", (event) => {
if (event.key === "Enter") {
console.log("Enter ditekan dengan isi:", input.value);
}
});input.addEventListener("input", () => {...}) dipicu setiap kali nilai berubah — termasuk penyalinan dan perekatan, bukan hanya ketikan. keydown memberi akses event.key untuk memeriksa tombol mana yang ditekan. Pola memeriksa event.key === "Enter" adalah dasar dari submit form via keyboard.
Beberapa event tidak menempel pada elemen tertentu, melainkan pada document atau window:
document.addEventListener("DOMContentLoaded", () => {
console.log("Dokumen selesai dimuat");
});
window.addEventListener("resize", () => {
console.log("Ukuran jendela berubah");
});document.addEventListener("DOMContentLoaded", ...) menjalankan kode begitu struktur dokumen siap — aman dipakai meski script diletakkan di head. window.addEventListener("resize", ...) merespons perubahan ukuran jendela. Kedua pola ini menjaga kode tetap berjalan di waktu yang tepat.
Saat sebuah elemen di dalam elemen lain diklik, event tidak berhenti di elemen itu — dia naik (bubbling) melewati semua induknya sampai ke document:
const luar = document.querySelector("#luar");
const dalam = document.querySelector("#dalam");
dalam.addEventListener("click", () => {
console.log("Klik pada: dalam");
});
luar.addEventListener("click", () => {
console.log("Klik pada: luar");
});Mengklik elemen dalam mencetak Klik pada: dalam lalu Klik pada: luar — handler induk ikut dipanggil karena event bergelembung ke atas. Ini normal dan berguna, tapi kadang tidak diinginkan. event.stopPropagation() menghentikan perambatan agar handler induk tidak terpanggil.
Beberapa elemen punya perilaku bawaan browser: a berpindah halaman, form mengirim request. preventDefault membatalkan perilaku itu:
const link = document.querySelector("#tautan");
link.addEventListener("click", (event) => {
event.preventDefault();
console.log("Navigasi default dibatalkan");
});event.preventDefault() membatalkan navigasi link tanpa menghentikan perambatan event. Bedakan dari stopPropagation: preventDefault membatalkan perilaku bawaan, stopPropagation menghentikan handler lain. Keduanya sering dipakai bersamaan untuk mengontrol penuh perilaku elemen.
Bayangkan sebuah daftar dengan ratusan item, dan setiap item mendapat handler sendiri. Saat item baru ditambahkan, handler harus dipasang ulang — membosankan dan membebani memori. Delegasi event menyelesaikan keduanya: pasang satu handler di induk, lalu cari tahu item mana yang diklik lewat event.target.
const daftar = document.querySelector("#daftar");
daftar.addEventListener("click", (event) => {
const item = event.target.closest("li");
if (item === null) return;
console.log("Item diklik:", item.textContent);
});event.target.closest("li") mencari elemen li terdekat dari titik klik, termasuk jika kalian mengklik teks di dalamnya. closest mengembalikan null jika tidak ada, dan periksa item === null mengabaikan klik yang tidak mengenai item. Satu handler melayani seluruh daftar.
Kekuatan utama delegasi: elemen yang ditambahkan setelah handler dipasang tetap terdeteksi, karena event menangkapnya saat bergelembung:
const daftar = document.querySelector("#daftar");
daftar.addEventListener("click", (event) => {
const item = event.target.closest("li");
if (item === null) return;
item.classList.toggle("selesai");
});
const tambah = document.querySelector("#tambah");
tambah.addEventListener("click", () => {
const itemBaru = document.createElement("li");
itemBaru.textContent = "Tugas baru";
daftar.append(itemBaru);
});Item yang ditambahkan lewat tombol tambah langsung bisa di-klik untuk men-toggle class selesai — tanpa perlu memasang handler baru. event.target.closest("li") di induk menangkap semuanya. Pola delegasi inilah yang dipakai di hampir semua aplikasi daftar interaktif.
Tip
Gunakan delegasi ketika elemen yang sama banyak (daftar, tabel, tombol berulang) atau ketika elemen muncul secara dinamis. Gunakan handler langsung ketika elemennya sedikit dan sudah pasti ada. Menghemat satu addEventListener di tempat yang tepat bisa mengurangi ratusan handler.
Episode 14 membuat halaman kalian hidup: mendaftarkan handler dengan addEventListener, membaca event object, mengenal event umum seperti click, input, dan keydown, memahami bubbling beserta stopPropagation, membatalkan perilaku default dengan preventDefault, serta menerapkan delegasi event yang efisien untuk elemen dinamis.
Inti yang harus dibawa pulang:
addEventListener mendaftar banyak handler tanpa menimpa yang lama.event.target adalah elemen yang terkena; event.currentTarget tempat handler.preventDefault membatalkan perilaku bawaan; stopPropagation menghentikan perambatan.closest berguna untuk menemukan elemen target dari titik klik.Di episode 15 selanjutnya kita akan membahas Fetch API dan AJAX — mengambil data dari server dengan fetch, membaca respons JSON, mengirim data dengan method POST, serta menangani status HTTP dengan benar. Inilah jembatan antara halaman kalian dan dunia luar.