JavaScript | BAB 6 Manipulasi DOM JS

Spoiler

Manipulasi DOM JavaScript - Tutorial Lengkap dengan Contoh Praktis

1. Memahami DOM (Document Object Model)

Document Object Model (DOM) adalah interface pemrograman untuk dokumen HTML dan XML. DOM merepresentasikan halaman web sebagai struktur tree yang terdiri dari node-node.

Contoh Struktur DOM:

<!DOCTYPE html>
<html>
  <head>
    <title>My title</title>
  </head>
  <body>
    <a href="#">My link</a>
    <h1>My header</h1>
  </body>
</html>

    

Penjelasan:

  1. Elemen root adalah <html>, yang memuat elemen <head> dan <body>.
  2. Di dalam <head>, terdapat elemen <title> yang berisi teks "My title".
  3. Di dalam <body>, terdapat elemen <a> dengan atribut href, yang menampilkan teks "My link", dan elemen <h1> yang berisi teks "My header".

2. Metode Akses Elemen DOM

2.1 Mengakses dengan ID

HTML:

<div id="myBox">Ini adalah box</div>
<div id="content">Ini adalah konten</div>
    

JavaScript:

// Mengakses elemen dengan ID
let boxElement = document.getElementById("myBox");
console.log(boxElement.innerHTML); // Output: "Ini adalah box"

// Mengubah konten elemen
boxElement.innerHTML = "Box telah diubah";

// Mengubah style
boxElement.style.backgroundColor = "yellow";
    

Penjelasan:

  1. getElementById() mengembalikan satu elemen spesifik
  2. Jika ID tidak ditemukan, mengembalikan null
  3. ID harus unik dalam satu halaman

2.2 Mengakses dengan Class Name

HTML:

<div class="item">Item 1</div>
<div class="item">Item 2</div>
<div class="item">Item 3</div>
    

JavaScript:

// Mengambil semua elemen dengan class "item"
let items = document.getElementsByClassName("item");

// Iterasi melalui elements
for(let i = 0; i < items.length; i++) {
    console.log(items[i].innerHTML);
    items[i].style.color = "blue";
}

// Menggunakan Array.from untuk metode array
Array.from(items).forEach(item => {
    item.addEventListener("click", function() {
        this.style.backgroundColor = "yellow";
    });
});
    

Penjelasan:

  1. getElementsByClassName() mengembalikan HTMLCollection
  2. Bisa ada banyak elemen dengan class yang sama
  3. HTMLCollection bersifat live (otomatis update)

2.3 Query Selector

HTML:

<div class="container">
    <p class="text">Paragraf 1</p>
    <p class="text highlight">Paragraf 2</p>
    <span class="text">Span text</span>
</div>
    

JavaScript:

// Mengambil elemen pertama yang cocok
let firstText = document.querySelector(".text");
console.log(firstText.innerHTML); // Output: "Paragraf 1"

// Mengambil semua elemen yang cocok
let allTexts = document.querySelectorAll(".text");
allTexts.forEach(text => {
    text.style.color = "red";
});

// Menggunakan selector yang lebih kompleks
let highlightedText = document.querySelector(".text.highlight");
console.log(highlightedText.innerHTML); // Output: "Paragraf 2"
    

Penjelasan:

  1. querySelector() mengembalikan elemen pertama yang cocok
  2. querySelectorAll() mengembalikan NodeList dari semua elemen yang cocok
  3. Bisa menggunakan selector CSS kompleks

3. Manipulasi Konten dan Atribut

3.1 Mengubah Konten

HTML:

<div id="content">Konten awal</div>
<div id="htmlContent">Teks <b>tebal</b></div>
    

JavaScript:

// Menggunakan innerText
let content = document.getElementById("content");
content.innerText = "Konten baru";

// Menggunakan innerHTML
let htmlContent = document.getElementById("htmlContent");
htmlContent.innerHTML = "Teks dengan <i>italic</i> dan <b>bold</b>";

// Menggunakan textContent
content.textContent = "Ini adalah text content";
    

Perbedaan:

  1. innerText memperhatikan styling CSS (hidden elements)
  2. innerHTML bisa mengandung HTML tags
  3. textContent mengambil konten text mentah

3.2 Manipulasi Atribut

HTML:

<img id="myImage" src="old.jpg" alt="Gambar lama">
<a id="myLink" href="https://example.com">Link</a>
    

JavaScript:

// Menggunakan setAttribute
let img = document.getElementById("myImage");
img.setAttribute("src", "new.jpg");
img.setAttribute("alt", "Gambar baru");

// Menggunakan properti langsung
let link = document.getElementById("myLink");
link.href = "https://newexample.com";

// Mengecek atribut
console.log(img.hasAttribute("alt")); // true
console.log(img.getAttribute("src")); // "new.jpg"

// Menghapus atribut
img.removeAttribute("alt");
    

Penjelasan:

  1. setAttribute() untuk mengubah atau menambah atribut
  2. getAttribute() untuk mengambil nilai atribut
  3. removeAttribute() untuk menghapus atribut
  4. Properti langsung lebih mudah tapi terbatas pada atribut standar

4. Event Handling

4.1 Event Click

HTML:

<button id="myButton">Klik Saya</button>
<div id="output"></div>
    

JavaScript:

let button = document.getElementById("myButton");
let output = document.getElementById("output");

// Cara 1: addEventListener
button.addEventListener("click", function(event) {
    output.textContent = "Button diklik!";
    console.log(event); // melihat object event
});

// Cara 2: onclick property
button.onclick = function() {
    output.textContent = "Button diklik (via onclick)!";
};

// Event dengan parameter
button.addEventListener("click", function(event) {
    // Menghentikan default action
    event.preventDefault();
    
    // Mendapatkan informasi event
    console.log(event.type); // "click"
    console.log(event.target); // element yang diklik
});
    

Penjelasan:

  1. addEventListener lebih fleksibel, bisa multiple handlers
  2. onclick lebih sederhana tapi hanya satu handler
  3. event object memberikan informasi tambahan tentang event

4.2 Form Events

HTML:

<form id="myForm">
    <input type="text" id="myInput" placeholder="Ketik sesuatu...">
    <button type="submit">Submit</button>
</form>
<div id="formOutput"></div>
    

JavaScript:

let form = document.getElementById("myForm");
let input = document.getElementById("myInput");
let formOutput = document.getElementById("formOutput");

// Form submit event
form.addEventListener("submit", function(event) {
    event.preventDefault(); // Mencegah form submit default
    formOutput.textContent = `Form disubmit dengan nilai: ${input.value}`;
});

// Input events
input.addEventListener("input", function(event) {
    formOutput.textContent = `Sedang mengetik: ${this.value}`;
});

input.addEventListener("focus", function() {
    this.style.backgroundColor = "lightyellow";
});

input.addEventListener("blur", function() {
    this.style.backgroundColor = "";
});
    

Penjelasan:

  1. preventDefault() mencegah halaman refresh saat submit
  2. input event terjadi setiap kali nilai berubah
  3. focus dan blur untuk styling interaktif

5. Contoh Aplikasi Praktis: Dynamic Todo List

HTML:

<div class="todo-app">
    <h2>Todo List</h2>
    <form id="todoForm">
        <input type="text" id="todoInput" placeholder="Tambah tugas baru...">
        <button type="submit">Tambah</button>
    </form>
    <ul id="todoList"></ul>
    <div id="todoStats"></div>
</div>
    

CSS:

.todo-app {
    max-width: 500px;
    margin: 20px auto;
    padding: 20px;
    border: 1px solid #ddd;
}

.completed {
    text-decoration: line-through;
    color: #888;
}

.todo-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 8px;
    margin: 4px 0;
    background-color: #f9f9f9;
}
    

JavaScript:

// Lanjutan JavaScript untuk Todo App
class TodoApp {
    constructor() {
        this.form = document.getElementById("todoForm");
        this.input = document.getElementById("todoInput");
        this.list = document.getElementById("todoList");
        this.stats = document.getElementById("todoStats");
        this.todos = [];
        
        this.setupEventListeners();
        this.updateStats();
    }

    setupEventListeners() {
        // Handle form submission
        this.form.addEventListener("submit", (e) => {
            e.preventDefault();
            this.addTodo();
        });

        // Handle item interactions using event delegation
        this.list.addEventListener("click", (e) => {
            const item = e.target.closest(".todo-item");
            if (!item) return;

            if (e.target.classList.contains("delete-btn")) {
                this.deleteTodo(item);
            } else if (e.target.classList.contains("toggle-btn")) {
                this.toggleTodo(item);
            }
        });
    }

    addTodo() {
        const text = this.input.value.trim();
        if (!text) return;

        const todo = {
            id: Date.now(),
            text: text,
            completed: false
        };

        this.todos.push(todo);
        this.renderTodo(todo);
        this.input.value = "";
        this.updateStats();
    }

    renderTodo(todo) {
        const li = document.createElement("li");
        li.className = "todo-item";
        li.dataset.id = todo.id;
        
        li.innerHTML = `
            
${todo.text}
`; this.list.appendChild(li); } deleteTodo(item) { const id = parseInt(item.dataset.id); this.todos = this.todos.filter(todo => todo.id !== id); item.remove(); this.updateStats(); } toggleTodo(item) { const id = parseInt(item.dataset.id); const todo = this.todos.find(t => t.id === id); if (!todo) return; todo.completed = !todo.completed; const todoText = item.querySelector(".todo-text"); todoText.classList.toggle("completed"); this.updateStats(); } updateStats() { const total = this.todos.length; const completed = this.todos.filter(todo => todo.completed).length; const pending = total - completed; this.stats.innerHTML = `

Total: ${total} | Selesai: ${completed} | Pending: ${pending}

`; } } // Inisialisasi aplikasi const todoApp = new TodoApp();

Penjelasan Komprehensif:

  1. Struktur Kelas
    • Menggunakan pendekatan OOP untuk organisasi kode yang lebih baik
    • Semua fungsionalitas terkait todo list dienkapsulasi dalam satu kelas
    • State (todos) dikelola secara terpusat
  2. Event Handling
    • Menggunakan event delegation untuk efisiensi
    • Penanganan berbagai jenis interaksi (tambah, hapus, toggle)
    • Validasi input sederhana
  3. Manipulasi DOM
    • Pembuatan elemen dinamis
    • Update UI berdasarkan state
    • Penggunaan template literals untuk HTML

6. Praktik Terbaik dalam Manipulasi DOM

6.1 Performa

Contoh Buruk:

// Manipulasi DOM dalam loop (buruk)
for(let i = 0; i < 1000; i++) {
    document.body.innerHTML += `
Item ${i}
`; }

Contoh Baik:

// Menggunakan DocumentFragment (baik)
const fragment = document.createDocumentFragment();
for(let i = 0; i < 1000; i++) {
    const div = document.createElement('div');
    div.textContent = `Item ${i}`;
    fragment.appendChild(div);
}
document.body.appendChild(fragment);
    

Penjelasan:

  • Gunakan DocumentFragment untuk batch updates
  • Minimalisir reflow dan repaint
  • Hindari manipulasi DOM berulang

6.2 Event Delegation

HTML:

<ul id="itemList">
    <li>Item 1</li>
    <li>Item 2</li>
    <li>Item 3</li>
</ul>
    

Contoh Buruk:

// Menambahkan event listener ke setiap item (buruk)
document.querySelectorAll('#itemList li').forEach(item => {
    item.addEventListener('click', function() {
        this.style.color = 'red';
    });
});
    

Contoh Baik:

// Menggunakan event delegation (baik)
document.getElementById('itemList').addEventListener('click', function(e) {
    if (e.target.tagName === 'LI') {
        e.target.style.color = 'red';
    }
});
    

Keuntungan Event Delegation:

  • Lebih efisien untuk memori
  • Otomatis bekerja untuk elemen dinamis
  • Kode lebih mudah dikelola

6.3 Keamanan

Hindari:

// JANGAN LAKUKAN INI!
element.innerHTML = userInput; // Berbahaya - XSS risk
    

Lakukan:

// Sanitasi input
function sanitizeInput(input) {
    const div = document.createElement('div');
    div.textContent = input;
    return div.innerHTML;
}

// Penggunaan yang aman
element.textContent = userInput;
// atau
element.innerHTML = sanitizeInput(userInput);
    

Tips Keamanan:

  • Selalu sanitasi input pengguna
  • Gunakan textContent untuk konten plain text
  • Validasi input sebelum memasukkan ke DOM

7. Debugging DOM

// Console methods untuk debugging
console.log(element); // Melihat elemen
console.dir(element); // Melihat properti elemen
console.table(nodeList); // Melihat collection dalam format tabel

// Debugging event listeners
function handleClick(e) {
    console.log('Event:', e);
    console.log('Target:', e.target);
    console.log('Current Target:', e.currentTarget);
    console.trace(); // Melihat stack trace
}

element.addEventListener('click', handleClick);
    

Tools Debugging:

  • Chrome DevTools Elements panel
  • Event Listeners tab
  • Breakpoints untuk manipulasi DOM