Phase 3 — JS
P20 · Pertemuan 20 dari 20

Event, Interaksi & Final Project

Menguasai event listener, manipulasi style via JS, localStorage, form validation, dan membangun website portofolio interaktif sebagai Final Project.

Phase
Phase 3 — JS
Topik
JavaScript Dasar
Durasi
90 Menit
Deadline Tugas
Hari Presentasi (H+5, pukul 10.00 WIB)
🎯Tujuan Pembelajaran
  • 01Menggunakan event listener: click, input, change, submit, keydown
  • 02Menguasai addEventListener dan removeEventListener
  • 03Memanipulasi style via JS: element.style, classList.add/remove/toggle
  • 04Membuat form validation dengan JavaScript
  • 05Menggunakan localStorage: setItem, getItem, removeItem
  • 06FINAL PROJECT: Website Portofolio Interaktif
📖Sub-topik & Materi
  • 01Event listener: addEventListener("event", callback)
  • 02Event types: click, input, change, submit, keydown, keyup, mouseover
  • 03classList: .add(), .remove(), .toggle(), .contains()
  • 04element.style untuk mengubah inline style via JS
  • 05Form validation: cek panjang input, format email, field kosong
  • 06localStorage: simpan data di browser (string only, JSON.stringify/parse)
💡Penjelasan Konsep
Konsep 1
Event Listener — addEventListener
addEventListener(event, callback) adalah cara menambahkan interaktivitas ke elemen. Event yang paling umum: "click" (klik tombol/elemen), "input" (setiap perubahan di input), "change" (nilai berubah dan blur), "submit" (form dikirim), "keydown" (tombol keyboard ditekan). Selalu gunakan e.preventDefault() di form submit agar halaman tidak reload.
javascript
"t-kw">const tombol = document.querySelector("t-st">'#tombol');
"t-kw">const input = document.querySelector("t-st">'#nama');
"t-kw">const form = document.querySelector("t-st">'form');

"t-kw">class="t-cm">// Klik
tombol.addEventListener("t-st">'click', () => {
  console.log("t-st">'Tombol diklik!');
});

"t-kw">class="t-cm">// Input: real-time
input.addEventListener("t-st">'input', (e) => {
  console.log("t-st">'Nilai:', e.target.value);
});

"t-kw">class="t-cm">// Form submit
form.addEventListener("t-st">'submit', (e) => {
  e.preventDefault(); "t-kw">class="t-cm">// cegah reload halaman!
  "t-kw">const nama = input.value.trim();
  "t-kw">if (nama === "t-st">'') {
    alert("t-st">'Nama tidak boleh kosong!');
    "t-kw">return;
  }
  console.log("t-st">`Halo, ${nama}!`);
});
Konsep 2
localStorage — Simpan Data di Browser
localStorage menyimpan data di browser yang tetap ada meski halaman ditutup/refresh. Hanya bisa menyimpan STRING. Untuk menyimpan array/object, gunakan JSON.stringify() saat menyimpan dan JSON.parse() saat membaca. Maksimal sekitar 5MB per origin.
javascript
"t-kw">class="t-cm">// Simpan data
localStorage.setItem("t-st">'nama', "t-st">'Ahmad');
localStorage.setItem("t-st">'skor', "t-st">'95');

"t-kw">class="t-cm">// Simpan object/array
"t-kw">const data = { nama: "t-st">'Ahmad', kota: "t-st">'Kediri', nilai: [80, 90, 85] };
localStorage.setItem("t-st">'siswa', JSON.stringify(data));

"t-kw">class="t-cm">// Baca data
"t-kw">const nama = localStorage.getItem("t-st">'nama');          "t-kw">class="t-cm">// "Ahmad"
"t-kw">const skor = Number(localStorage.getItem("t-st">'skor')); "t-kw">class="t-cm">// 95
"t-kw">const siswa = JSON.parse(localStorage.getItem("t-st">'siswa')); "t-kw">class="t-cm">// object

"t-kw">class="t-cm">// Hapus
localStorage.removeItem("t-st">'nama');
localStorage.clear(); "t-kw">class="t-cm">// hapus semua
Konsep 3
Fetch API — Ambil Data dari Internet
fetch() mengambil data dari URL (API) secara asynchronous. Gunakan async/await untuk kode yang lebih mudah dibaca. Selalu tambahkan try-catch untuk handle error. API publik yang bisa dipakai untuk latihan: JSONPlaceholder, Open Trivia DB, REST Countries.
javascript
"t-kw">class="t-cm">// Fetch dengan "t-kw">async/"t-kw">await + error handling
"t-kw">async "t-kw">function ambilData() {
  try {
    "t-kw">const response = "t-kw">await fetch("t-st">'https:"t-kw">class="t-cm">//jsonplaceholder.typicode.com/users');
    
    "t-kw">if (!response.ok) {
      throw "t-kw">new Error("t-st">`Error: ${response.status}`);
    }
    
    "t-kw">const data = "t-kw">await response.json();
    tampilkanData(data);
  } catch (error) {
    console.error("t-st">'Gagal fetch:', error.message);
    document.getElementById("t-st">'container').innerHTML = 
      "t-st">'<p "t-kw">class="error">Gagal memuat data. Coba lagi.</p>';
  }
}

"t-kw">function tampilkanData(users) {
  "t-kw">const container = document.getElementById("t-st">'container');
  container.innerHTML = users.map(user => "t-st">`
    <div "t-kw">class="kartu">
      <h2>${user.name}</h2>
      <p>${user.email}</p>
    </div>
  `).join("t-st">'');
}

ambilData();
💻Contoh Kode Lengkap
javascript
"t-kw">class="t-cm">// === Event Listener ===
"t-kw">const tombol = document.getElementById("t-st">'btn-dark');
tombol.addEventListener("t-st">'click', () => {
  document.body.classList.toggle("t-st">'dark-mode');
  "t-kw">const isDark = document.body.classList.contains("t-st">'dark-mode');
  localStorage.setItem("t-st">'darkMode', isDark);
  tombol.textContent = isDark ? "t-st">'☀️ Light' : "t-st">'🌙 Dark';
});

"t-kw">class="t-cm">// Load preferensi dark mode saat halaman dibuka
window.addEventListener("t-st">'load', () => {
  "t-kw">if (localStorage.getItem("t-st">'darkMode') === "t-st">'true') {
    document.body.classList.add("t-st">'dark-mode');
  }
});

"t-kw">class="t-cm">// === Form Validation ===
"t-kw">const form = document.querySelector("t-st">'form');
form.addEventListener("t-st">'submit', (e) => {
  e.preventDefault(); "t-kw">class="t-cm">// Cegah reload halaman
  "t-kw">const nama = document.getElementById("t-st">'nama').value.trim();
  "t-kw">const email = document.getElementById("t-st">'email').value.trim();
  "t-kw">if (!nama) {
    alert("t-st">'Nama tidak boleh kosong!');
    "t-kw">return;
  }
  "t-kw">if (!email.includes("t-st">'@')) {
    alert("t-st">'Format email tidak valid!');
    "t-kw">return;
  }
  console.log("t-st">'Form berhasil dikirim:', { nama, email });
});
Latihan Kelas · Buat dark mode toggle dan form validation untuk halaman portofolio
1
Tambahkan tombol dark mode toggle di navbar halaman
2
addEventListener click untuk toggle class "dark-mode" di body
3
Simpan preferensi dark mode ke localStorage
4
Load preferensi dari localStorage saat halaman dibuka (window load)
5
Buat form contact dengan validasi: nama tidak kosong, email valid
📝 Final Project — Website Portofolio Interaktif
⏰ Deadline: Hari Presentasi (H+5, pukul 10.00 WIB)

Bangun website portofolio pribadi lengkap: multi-section (Hero, About, Skills, Projects, Contact), responsive, dark mode toggle (tersimpan di localStorage), form contact dengan validasi JS, dan minimal 1 fitur interaktif tambahan. Deploy ke GitHub Pages.

Kriteria PenilaianPoin
Struktur HTML semantic & valid (multi-section lengkap)20
CSS responsif 3 breakpoint dengan Flexbox/Grid20
Dark mode toggle berfungsi & tersimpan di localStorage20
Form contact dengan validasi JavaScript berfungsi20
Live di GitHub Pages & dipresentasikan15
Kerapian kode: indentasi, komentar, penamaan deskriptif5
Total100
⚠️Kesalahan yang Sering Dibuat
Lupa e.preventDefault() di form submit — halaman reload dan semua input hilang
Fetch tanpa try-catch — jika internet mati atau API error, program crash tanpa pesan yang jelas
Lupa await sebelum fetch() atau .json() — mendapat Promise bukan data aktual
localStorage menyimpan object langsung tanpa JSON.stringify() — tersimpan sebagai "[object Object]"
Memanggil event listener berkali-kali (misal di dalam loop) — handler terpasang ganda
💡 Tips Instruktur
Mulai dari mobile, tambahkan responsivitas ke atas (mobile-first)
Gunakan semua CSS Variables dari P09 untuk konsistensi warna
localStorage hanya menyimpan string — JSON.stringify() untuk object
e.preventDefault() wajib di submit listener agar halaman tidak reload
📋 Checklist Belajar
Pahami konsep sebelum latihan
Coba kode sendiri tanpa copy-paste
Kerjakan tugas sebelum deadline
Tanya instruktur jika ada yang belum jelas
Parelabs Academy - Kursus Bahasa Inggris Terbaik Offline & Online