Masukkan Password
43 Pilih Pendekatan Penanganan Peristiwa
Lecture ini sangat penting karena menjawab pertanyaan yang sebelumnya masih menggantung:
Kapan kita menggunakan inline event handler, event handler property, dan
addEventListener()?
Dan ada satu konsep besar yang menjadi inti lecture ini:
Cara menangani event harus disesuaikan dengan apakah element tersebut static atau dynamically generated.
Mari kita bedah pelan-pelan.
1. Review: kita sudah punya 3 cara menangani event
Sebelumnya kita sudah belajar:
1. Inline event handler
<button onclick="calculateEmi()">
Calculate EMI
</button>
2. Event handler property
button.onclick = calculateEmi;
3. addEventListener()
button.addEventListener("click", calculateEmi);
Ketiganya bisa digunakan untuk menangani event.
Pertanyaannya:
Mana yang harus kita pilih?
Lecture ini mencoba menjawabnya.
2. Kita mulai dari kasus EMI Calculator
Di project kita ada tab:
Home
EMI Calculator
Apply for Loan
Ketika masuk ke EMI Calculator, ada form:
Principal Amount
Loan Duration
Interest Rate
[ Calculate EMI ]
User mengisi:
Principal = 200,000
Duration = 60 bulan
Interest = 10.4%
Kemudian klik:
[ Calculate EMI ]
Kita ingin:
Klik Calculate EMI
↓
calculateEmi()
↓
hitung EMI
↓
hitung total payable
↓
alert(...)
3. Function calculateEmi()
Lecture sudah membuat function untuk menghitung EMI.
Secara konsep kira-kira seperti ini:
function calculateEmi() {
let principal = document.getElementById("amount").value;
let duration = document.getElementById("duration").value;
let rate = document.getElementById("roi").value;
// perhitungan EMI...
alert(...);
}
Mari kita pahami bagian pentingnya.
4. Mengambil value dari input
Misalnya HTML:
<input id="amount">
<input id="duration">
<input id="roi">
JavaScript:
document.getElementById("amount")
mengambil element input.
Kemudian:
.value
mengambil nilai yang dimasukkan user.
Jadi:
let principal = document.getElementById("amount").value;
artinya:
“Ambil input dengan ID
amount, kemudian ambil nilai yang sedang dimasukkan user.”
5. Perhatikan: .value biasanya berupa String
Ini nyambung dengan lecture tentang type coercion.
Misalnya user mengetik:
200000
Ketika kita mengambil:
input.value
hasilnya biasanya:
"200000"
bukan:
200000
Yang pertama adalah String.
Yang kedua adalah Number.
Jadi dalam aplikasi nyata, kita sering melakukan konversi:
let principal = Number(document.getElementById("amount").value);
Tetapi untuk fokus lecture ini, yang paling penting adalah memahami bagaimana element dan event bekerja.
6. toFixed(2)
Lecture juga menggunakan:
.toFixed(2)
Fungsinya untuk menentukan jumlah angka setelah desimal.
Contoh:
let x = 123.456789;
x.toFixed(2);
hasilnya:
"123.46"
Artinya:
Tampilkan dua angka setelah titik desimal.
Contoh lain:
100.5.toFixed(2)
menjadi:
"100.50"
Jadi:
toFixed(2)
↓
maksimal/tampilkan 2 digit setelah desimal
Catatan: hasil toFixed() adalah String, bukan Number.
7. Sekarang masalah utamanya: bagaimana menjalankan calculateEmi() saat tombol diklik?
Kita perlu mengambil tombol:
<button class="calculate-emi">
Calculate EMI
</button>
Kemudian kita bisa melakukan:
let button = document.querySelector(".calculate-emi");
Setelah mendapatkan button, kita ingin memasang event.
Misalnya:
button.addEventListener("click", calculateEmi);
Kelihatannya benar.
Tetapi ternyata ada masalah besar.
8. Kenapa addEventListener() tidak bekerja?
Kalau kamu ingat lecture DOM sebelumnya, kita memiliki sistem tab.
Ketika halaman pertama kali dibuka, HTML memiliki:
Homepage
EMI Calculator
Apply for Loan
Tetapi function:
renderSelectedSection("homepage");
melakukan sesuatu seperti:
mainSectionArea.innerHTML = "";
Kemudian memasukkan Homepage.
Akibatnya:
Awalnya:
mainSectionArea
├── Homepage
├── EMI Calculator
└── Apply for Loan
↓ renderSelectedSection("homepage")
mainSectionArea
└── Homepage
Jadi:
EMI Calculator
Apply for Loan
dihapus dari DOM saat ini.
9. Ini sangat penting: HTML source vs DOM
Ini harus benar-benar kamu pahami.
File HTML kita masih memiliki:
<section class="emi-calculator-page">
...
</section>
Tetapi JavaScript sudah menghapus section tersebut dari DOM.
Jadi:
HTML file
│
├── Homepage
├── EMI Calculator
└── Apply for Loan
↓ browser + JavaScript
CURRENT DOM
│
└── Homepage
HTML file-nya tidak berubah.
Yang berubah adalah DOM yang sedang aktif di browser.
10. Akibatnya querySelector() bisa menghasilkan null
Misalnya kita menulis:
let calculateButton =
document.querySelector(".calculate-emi");
Tetapi saat kode tersebut dijalankan, EMI Calculator belum ada di DOM.
Maka:
calculateButton
berisi:
null
Kemudian kalau kita melakukan:
calculateButton.addEventListener("click", calculateEmi);
JavaScript mencoba melakukan:
null.addEventListener(...)
Tentu tidak bisa.
Akibatnya muncul error seperti:
Cannot read properties of null
(reading 'addEventListener')
11. “Tapi class-nya memang ada di HTML!”
Nah, ini jebakan yang sangat umum.
Kamu mungkin berpikir:
“Tapi saya yakin
.calculate-emiada di HTML!”
Benar.
Tetapi:
document.querySelector(...)
mencari di DOM saat ini, bukan membaca file HTML mentah dari hard disk.
Kalau element sudah dihapus dari DOM:
document.querySelector(".calculate-emi")
tidak akan menemukannya.
Hasilnya:
null
12. Lalu lecture mencoba memindahkan addEventListener()
Lecture kemudian mencoba memasang listener sebelum section dihapus.
Misalnya:
let calculateButton =
document.querySelector(".calculate-emi");
calculateButton.addEventListener("click", calculateEmi);
renderSelectedSection("homepage");
Sekarang tidak ada error.
Kenapa?
Karena saat ini button masih ada:
HTML/DOM
↓
Calculate EMI button ada
↓
querySelector()
↓
button ditemukan
↓
addEventListener() berhasil
↓
baru setelah itu section dihapus
Tetapi…
tetap tidak bekerja.
Nah, ini bagian paling penting.
13. Kenapa tidak error tetapi tetap tidak bekerja?
Karena sekarang terjadi sesuatu yang lebih halus.
Awalnya browser membuat object DOM untuk button:
Button Object A
Kita memasang:
button.addEventListener("click", calculateEmi);
Listener menempel pada:
Button Object A
Kemudian:
mainSectionArea.innerHTML = "";
menghapus section EMI dari DOM.
Akibatnya:
Button Object A
↓
dikeluarkan dari DOM
14. Kemudian user membuka EMI Calculator lagi
Saat user klik tab EMI Calculator:
EMI Calculator
↓
renderSelectedSection()
↓
HTML EMI dimasukkan kembali
↓
browser membuat DOM objects baru
Sekarang button-nya bukan object lama.
Sekarang:
Button Object B
Jadi:
Object A
↓
listener sudah dipasang
↓
dihapus dari DOM
Object B
↓
masuk ke DOM
↓
TIDAK punya listener
Ini akar masalahnya.
15. Analogi paling mudah: rumah dan furnitur
Bayangkan button adalah sebuah kursi.
Pertama:
Rumah
└── Kursi A
Kamu menempelkan stiker:
"KALAU DIDUDUKI → lakukan sesuatu"
Kemudian rumah dibongkar.
Kursi A
↓
dibuang
Kemudian rumah dibangun ulang:
Rumah baru
└── Kursi B
Walaupun bentuk kursinya sama, Kursi B bukan Kursi A.
Stiker yang kamu tempel di Kursi A tidak otomatis berpindah ke Kursi B.
Begitu juga DOM object.
DOM Object A ≠ DOM Object B
Walaupun keduanya berasal dari HTML yang sama.
16. Ini berlaku untuk onclick juga
Lecture kemudian mencoba:
button.onclick = calculateEmi;
Ternyata tetap tidak bekerja.
Kenapa?
Karena masalahnya bukan:
addEventListener vs onclick
Masalah sebenarnya adalah:
Kita memasang event handler pada object DOM lama, kemudian object tersebut dihapus dan dibuat object baru.
Jadi:
addEventListener()
❌
onclick property
❌
keduanya memiliki masalah yang sama kalau dipasang pada DOM object yang kemudian dihapus dan dibuat ulang.
17. Jadi apa itu “dynamically generated content”?
Dalam project ini, content seperti:
Homepage
EMI Calculator
Apply for Loan
tidak semuanya selalu berada di DOM.
JavaScript secara dinamis menghapus dan memasukkan section.
Misalnya:
Klik Home
↓
DOM berisi Home
Klik EMI
↓
Home dihapus
EMI dimasukkan
Klik Apply
↓
EMI dihapus
Apply dimasukkan
Inilah yang dimaksud:
Dynamically generated/manipulated content
Element DOM dibuat/dimasukkan atau dihapus selama program berjalan.
18. Static content vs dynamic content
Sekarang kita sampai pada konsep utama lecture.
Static content
Element sudah ada di DOM dan tetap berada di DOM.
Contoh:
<header>Welcome</header>
Kalau element ini tidak dihapus/dibuat ulang, kita bisa dengan aman memasang:
header.addEventListener("click", ...);
Dynamic content
Element dibuat/dimasukkan/dihapus oleh JavaScript.
Contoh:
mainSectionArea.innerHTML = someHTML;
Element yang berada di dalam HTML tersebut bisa menjadi object DOM baru.
Maka listener yang dipasang pada object lama tidak otomatis berpindah.
19. Lalu mengapa inline event handler bekerja?
Ini bagian menarik.
Lecture akhirnya menggunakan:
<button
class="calculate-emi"
onclick="calculateEmi()">
Calculate EMI
</button>
Kenapa ini bisa bekerja?
Karena onclick sekarang menjadi bagian dari markup HTML yang dimasukkan setiap kali section dibuat.
Ketika section EMI dibuat:
HTML EMI dibuat
↓
Button dibuat
↓
Button memiliki onclick="calculateEmi()"
↓
DOM object baru dibuat
↓
onclick sudah ada pada markup tersebut
Kemudian jika section dihapus:
Button lama dihapus
Ketika section dibuat lagi:
Button baru dibuat
↓
HTML-nya kembali memiliki onclick
↓
Button baru juga memiliki event handler
Jadi tidak peduli berapa kali button dibuat ulang, markup-nya sudah membawa event handler.
20. Gambaran sederhananya
Event listener/property
Button A
↓
pasang listener
↓
Button A dihapus
↓
Button B dibuat
↓
Button B tidak punya listener
❌ Tidak bekerja.
Inline event handler
HTML dengan onclick
↓
Button A dibuat
↓
onclick tersedia
Button A dihapus
↓
HTML dengan onclick
↓
Button B dibuat
↓
onclick tersedia lagi
✅ Bekerja untuk pola dynamic rendering seperti pada contoh lecture.
21. Ini bukan berarti addEventListener() buruk
Penting banget: jangan sampai kesimpulannya:
“
addEventListener()tidak bagus.”
Bukan itu.
addEventListener() justru sangat penting dan umum digunakan.
Masalahnya adalah kapan dan di mana listener dipasang.
Untuk element static:
button.addEventListener("click", calculateEmi);
sangat bagus.
Untuk element yang dihapus dan dibuat ulang seperti contoh ini:
button lama → dihapus
button baru → dibuat
listener yang dipasang pada button lama tidak otomatis ikut ke button baru.
22. Jadi kapan menggunakan masing-masing?
Menurut konteks lecture ini:
Static content
Bisa menggunakan:
event handler property
atau:
addEventListener()
Contoh:
const header = document.querySelector("header");
header.addEventListener("mouseover", function() {
header.style.color = "black";
});
Kalau header tidak pernah dihapus dan dibuat ulang, listener tetap terpasang pada object yang sama.
Dynamic content
Dalam pola project lecture ini:
inline event handler
adalah pendekatan yang digunakan.
Contoh:
<button onclick="calculateEmi()">
Karena ketika element baru dibuat, event handler sudah ikut berada di markup.
23. Tapi ada catatan penting tentang praktik modern
Di sini saya ingin memberi sedikit catatan teknis, supaya kamu tidak mendapatkan pemahaman yang terlalu kaku.
Jangan mengambil kesimpulan:
“Kalau dynamic content, selalu harus pakai inline.”
Dalam JavaScript modern, kita sering menggunakan event delegation dengan addEventListener().
Contohnya nanti bisa seperti:
container.addEventListener("click", function(event) {
if (event.target.matches(".calculate-emi")) {
calculateEmi();
}
});
Listener dipasang pada element yang tidak ikut dihapus, kemudian event dari child ditangani melalui event bubbling.
Ini justru salah satu cara modern yang sangat berguna untuk dynamic content.
Tetapi kalau course kamu belum membahas:
- event bubbling
- event target
- event delegation
jangan dipaksakan sekarang.
Kemungkinan itu akan dibahas di lecture berikutnya atau bagian lanjutan.
Untuk memahami lecture saat ini, ikuti model yang diberikan course:
Static → property / addEventListener
Dynamic → inline handler
Nanti ketika sudah belajar event delegation, pemahamanmu akan menjadi lebih lengkap.
24. Perbedaan object lama dan object baru
Ini adalah konsep yang menurut saya paling penting dari seluruh lecture.
Misalnya:
let button = document.querySelector(".calculate-emi");
Saat itu:
button
↓
DOM Object A
Kemudian:
mainSectionArea.innerHTML = "";
Object A tidak lagi menjadi bagian dari DOM.
Kemudian kita memasukkan HTML baru:
mainSectionArea.innerHTML = "...";
Browser membuat:
DOM Object B
Jadi:
Sebelumnya:
button → Object A
Setelah render ulang:
button → Object B
Object B adalah object yang berbeda.
25. Ini berhubungan dengan reference yang sudah kita pelajari
Misalnya:
let button = document.querySelector(".calculate-emi");
Variabel:
button
menyimpan reference ke object tertentu.
Bisa dibayangkan:
button
│
↓
[ DOM Object A ]
Kalau object A dihapus dari DOM:
button
│
↓
[ DOM Object A ] ← sudah tidak ada di document
Kemudian browser membuat object baru:
[ DOM Object B ]
Variabel button yang lama tidak otomatis berubah menjadi:
button
│
↓
[ DOM Object B ]
Itulah kenapa listener lama tidak berpindah.
26. Kenapa function calculateEmi tidak perlu dipanggil?
Lecture menulis:
button.addEventListener("click", calculateEmi);
bukan:
button.addEventListener("click", calculateEmi());
Ini sama seperti lecture callback sebelumnya.
Benar:
calculateEmi
Artinya:
Berikan function ini kepada event listener.
Salah untuk kasus ini:
calculateEmi()
Artinya:
Jalankan function sekarang.
Kita ingin:
Sekarang:
jangan jalankan
Nanti ketika click:
jalankan
Maka:
button.addEventListener("click", calculateEmi);
27. Kenapa function calculateEmi() dibuat di luar?
Lecture juga menjelaskan alasan lain.
Misalnya function:
function calculateEmi() {
...
}
mungkin ingin digunakan di tempat lain.
Misalnya:
Calculate EMI button
↓
calculateEmi()
Apply for Loan
↓
calculateEmi()
Jadi kita tidak membuat:
button.addEventListener("click", function() {
// semua kode EMI di sini
});
karena function perhitungannya mungkin ingin digunakan kembali.
Ini kembali ke konsep:
Function dibuat untuk reusable code.
28. Connection dengan lecture Function
Kita sudah belajar:
function calculateEmi() {
...
}
adalah function declaration.
Kemudian:
button.addEventListener("click", calculateEmi);
function tersebut diberikan sebagai callback.
Jadi:
Function
↓
calculateEmi
↓
diberikan sebagai callback
↓
addEventListener
↓
click terjadi
↓
calculateEmi dipanggil
29. Connection dengan lecture Scope
Ini juga berkaitan dengan scope.
Sebelumnya kita belajar bahwa variabel di luar function bisa digunakan oleh function di dalamnya selama masih berada dalam scope yang sesuai.
Sekarang konsepnya sedikit berbeda:
function calculateEmi() {
...
}
function ini dibuat di luar event handler sehingga bisa digunakan oleh beberapa bagian program.
Misalnya:
button.addEventListener("click", calculateEmi);
dan nanti:
someOtherButton.addEventListener("click", calculateEmi);
Keduanya bisa menggunakan function yang sama.
30. Perbandingan akhir
Untuk konteks yang diajarkan lecture:
| Kondisi | Pendekatan |
|---|---|
| Static DOM element | addEventListener() ✅ |
| Static DOM element | Event handler property ✅ |
| Dynamic element yang dibuat ulang | Inline handler dalam contoh course ✅ |
| Dynamic element | addEventListener() langsung pada element yang nanti dihapus ❌ |
| Dynamic element | onclick property langsung pada object yang nanti dihapus ❌ |
| Dynamic element | Event delegation dengan addEventListener() ⭐ teknik modern, dipelajari kemudian |
31. Jangan salah memahami “static”
Static bukan berarti:
“Element tersebut tidak boleh berubah sama sekali.”
Misalnya:
button.style.backgroundColor = "red";
Button tetap static selama object DOM-nya tidak dihancurkan/dibuat ulang.
Jadi:
Static
=
DOM object tetap ada
Bukan:
Static
=
tampilan tidak pernah berubah
32. Dynamic bukan sekadar “style berubah”
Misalnya:
button.style.color = "red";
Ini tidak otomatis berarti button menjadi dynamic content dalam pengertian lecture.
Yang menjadi masalah adalah ketika element/object-nya:
dihapus
atau
dibuat ulang
Contohnya:
container.innerHTML = "";
kemudian:
container.innerHTML = "<button>...</button>";
Ini menghasilkan DOM object baru.
33. Kesalahan pemahaman yang harus dihindari
❌ “Kalau HTML punya element, querySelector() pasti menemukannya.”
Tidak.
querySelector() mencari DOM saat ini.
❌ “Kalau class-nya sama, berarti object-nya sama.”
Tidak.
Bisa saja:
Button A
dihapus, lalu:
Button B
dibuat dengan HTML/class yang sama.
Tetap dua object berbeda.
❌ “Listener akan otomatis mengikuti element baru.”
Tidak.
Kalau kamu melakukan:
button.addEventListener(...)
listener terpasang pada object tersebut.
Object baru tidak otomatis mendapatkan listener tersebut.
❌ “addEventListener() tidak bisa digunakan untuk dynamic content.”
Terlalu general.
Yang benar:
Memasang listener langsung pada dynamic element yang nantinya dihapus/recreated dapat menyebabkan listener hilang.
Teknik seperti event delegation dapat menangani dynamic content dengan addEventListener().
34. Visualisasi keseluruhan bug pada lecture
Ini menurut saya diagram yang paling penting:
PAGE LOAD
↓
HTML → DOM Object
↓
Calculate Button A
↓
addEventListener()
↓
Listener terpasang
↓
renderSelectedSection()
↓
innerHTML = ""
↓
Button A DIHAPUS
↓
User klik
↓
buka EMI Calculator
↓
Button B DIBUAT
↓
Button B ≠ Button A
↓
Button B tidak punya
listener dari Button A
↓
❌ tidak jalan
Sedangkan inline:
HTML template
↓
onclick="calculateEmi()"
↓
Button A dibuat
↓
Button A dihapus
↓
Button B dibuat
↓
HTML template dibuat lagi
↓
onclick="calculateEmi()" ada lagi
↓
✅ jalan
35. Lalu apa rekomendasi yang harus kamu pegang sekarang?
Untuk materi course saat ini, pegang aturan berikut:
EVENT HANDLING
│
┌──────────┴──────────┐
↓ ↓
STATIC DOM DYNAMIC DOM
│ │
┌────┴────┐ ↓
↓ ↓ Inline handler
onclick addEventListener
property
Tapi tambahkan catatan kecil di kepala:
Dynamic DOM
↓
nanti bisa ditangani secara modern
dengan event delegation
↓
addEventListener()
Jadi jangan membenci addEventListener() 😄
Justru nanti kemungkinan besar kamu akan sering menggunakannya.
🧠 Ringkasan super penting
Kalau besok kamu lupa hampir semua isi lecture ini, ingat 5 hal berikut:
1. Ada tiga cara event handling
Inline
Event handler property
addEventListener()
2. Untuk static content
Kita bisa menggunakan:
element.onclick = ...
atau:
element.addEventListener("click", ...)
3. Masalah muncul ketika element dihapus dan dibuat ulang
Misalnya:
Button A
↓
listener dipasang
↓
Button A dihapus
↓
Button B dibuat
Button B tidak otomatis memiliki listener Button A.
4. Itu yang terjadi pada EMI Calculator
renderSelectedSection()
↓
section dihapus
↓
EMI button ikut dihapus
↓
EMI section dibuka lagi
↓
button baru dibuat
5. Untuk pola dynamic rendering dalam lecture ini
Inline handler:
<button onclick="calculateEmi()">
dibawa bersama HTML setiap kali element dibuat.
🎯 Kalimat yang paling penting dari lecture ini
Event listener/property menempel pada DOM object tertentu. Kalau object tersebut dihapus dan dibuat ulang, object baru tidak otomatis memiliki listener dari object lama.
Dan inilah alasan kenapa kita harus mempertimbangkan bagaimana lifecycle DOM element tersebut sebelum memilih cara menangani event.
STATIC ELEMENT
→ addEventListener / event handler property
ELEMENT YANG DIHAPUS & DIBUAT ULANG
→ listener langsung pada object lama bisa hilang
→ course ini menggunakan inline handler
→ teknik modern berikutnya: event delegation
Dengan memahami bagian “object lama vs object baru”, sebenarnya kamu sudah memahami inti lecture ini. Ini juga menjadi fondasi penting sebelum masuk ke topik event bubbling, event propagation, dan event delegation.