Bab 4: DOM Manipulation

Bab 4: DOM Manipulation

4.1 Pengenalan Document Object Model (DOM)

4.1.1 Apa itu DOM?

  • Struktur representasi dokumen HTML/XML

  • Tree structure dari dokumen

  • Node types dan hierarki

  • Window object vs Document object

  • DOM Level dan standards

4.1.2 DOM Tree Structure

// Contoh struktur DOM
/*
document
    ├── html
    │   ├── head
    │   │   ├── title
    │   │   └── meta
    │   └── body
    │       ├── div
    │       ├── p
    │       └── script
*/

// Mengakses struktur DOM
console.log(document.documentElement); // html element
console.log(document.head); // head element
console.log(document.body); // body element

4.2 Seleksi Element

4.2.1 Basic Selectors

// By ID
const elementById = document.getElementById('myId');

// By Class Name
const elementsByClass = document.getElementsByClassName('myClass');

// By Tag Name
const elementsByTag = document.getElementsByTagName('div');

// Query Selector
const element = document.querySelector('.myClass');
const elements = document.querySelectorAll('.myClass');

// Query Selector dengan Complex Selectors
const complexElement = document.querySelector('div.myClass > p:first-child');

4.2.2 Advanced Selection Methods

// Closest parent matching selector
const closestParent = element.closest('.container');

// Direct children
const children = element.children;

// First and last child
const firstChild = element.firstElementChild;
const lastChild = element.lastElementChild;

// Siblings
const nextSibling = element.nextElementSibling;
const previousSibling = element.previousElementSibling;

// Parent
const parent = element.parentElement;

4.3 Modifikasi Element

4.3.1 Content Modification

// Text content
element.textContent = 'New text';

// Inner HTML
element.innerHTML = '<span>New HTML</span>';

// Outer HTML
element.outerHTML = '<div>Replace entire element</div>';

// Value (untuk form elements)
inputElement.value = 'New value';

4.3.2 Attributes Manipulation

// Get attribute
const value = element.getAttribute('data-id');

// Set attribute
element.setAttribute('data-id', '123');

// Remove attribute
element.removeAttribute('data-id');

// Check attribute existence
const hasAttribute = element.hasAttribute('data-id');

// Data attributes
element.dataset.customData = 'value';
console.log(element.dataset.customData);

4.3.3 Style Manipulation

// Direct style
element.style.backgroundColor = 'red';
element.style.fontSize = '16px';

// Classes
element.classList.add('active');
element.classList.remove('inactive');
element.classList.toggle('visible');
element.classList.replace('old', 'new');
element.classList.contains('active');

// Multiple classes
element.className = 'class1 class2 class3';

4.4 Creating dan Removing Elements

4.4.1 Creating Elements

// Create new element
const newDiv = document.createElement('div');

// Create text node
const textNode = document.createTextNode('Hello World');

// Create element with content
const paragraph = document.createElement('p');
paragraph.textContent = 'New paragraph';

// Create complex structure
const container = document.createElement('div');
container.innerHTML = `
    <h2>Title</h2>
    <p>Paragraph 1</p>
    <p>Paragraph 2</p>
`;

4.4.2 Adding Elements to DOM

// Append at end
parent.appendChild(newElement);

// Insert before specific element
parent.insertBefore(newElement, referenceElement);

// Insert at specific position
parent.insertAdjacentElement('beforebegin', element);
parent.insertAdjacentElement('afterbegin', element);
parent.insertAdjacentElement('beforeend', element);
parent.insertAdjacentElement('afterend', element);

// Insert HTML
element.insertAdjacentHTML('beforeend', '<div>New content</div>');

4.4.3 Removing Elements

// Remove element
element.remove();

// Remove child
parent.removeChild(child);

// Clear all children
while (element.firstChild) {
    element.removeChild(element.firstChild);
}

4.5 Event Handling

4.5.1 Basic Event Handling

// Adding event listener
element.addEventListener('click', function(event) {
    console.log('Clicked!');
});

// Removing event listener
const handler = function(event) {
    console.log('Handled!');
};
element.addEventListener('click', handler);
element.removeEventListener('click', handler);

// Inline event handling (not recommended)
element.onclick = function() {
    console.log('Clicked!');
};

4.5.2 Event Object Properties

element.addEventListener('click', function(event) {
    // Event properties
    console.log(event.type);        // Type of event
    console.log(event.target);      // Element that triggered event
    console.log(event.currentTarget); // Element handling event
    console.log(event.clientX);     // Mouse X coordinate
    console.log(event.clientY);     // Mouse Y coordinate
    
    // Prevent default behavior
    event.preventDefault();
    
    // Stop propagation
    event.stopPropagation();
});

4.5.3 Event Types

// Mouse events
element.addEventListener('click', handler);
element.addEventListener('dblclick', handler);
element.addEventListener('mousedown', handler);
element.addEventListener('mouseup', handler);
element.addEventListener('mouseover', handler);
element.addEventListener('mouseout', handler);
element.addEventListener('mousemove', handler);

// Keyboard events
element.addEventListener('keydown', handler);
element.addEventListener('keyup', handler);
element.addEventListener('keypress', handler);

// Form events
element.addEventListener('submit', handler);
element.addEventListener('change', handler);
element.addEventListener('input', handler);
element.addEventListener('focus', handler);
element.addEventListener('blur', handler);

// Document/Window events
window.addEventListener('load', handler);
window.addEventListener('DOMContentLoaded', handler);
window.addEventListener('resize', handler);
window.addEventListener('scroll', handler);

4.6 Event Bubbling dan Capturing

4.6.1 Event Flow

// Bubbling phase (default)
parent.addEventListener('click', function(event) {
    console.log('Parent clicked - bubbling');
});

// Capturing phase
parent.addEventListener('click', function(event) {
    console.log('Parent clicked - capturing');
}, true);

// Stop bubbling
child.addEventListener('click', function(event) {
    event.stopPropagation();
    console.log('Child clicked - event stopped');
});

4.7 DOM Traversal

4.7.1 Node Navigation

// Node relationships
const parent = node.parentNode;
const children = node.childNodes;
const siblings = node.siblings;

// Element navigation
const firstChild = element.firstElementChild;
const lastChild = element.lastElementChild;
const parent = element.parentElement;
const nextSibling = element.nextElementSibling;
const previousSibling = element.previousElementSibling;

4.8 Praktik dan Latihan

4.8.1 Project: Dynamic Form Generator

class FormGenerator {
    constructor(container) {
        this.container = container;
    }
    
    addField(type, label, options = {}) {
        const field = document.createElement('div');
        // Implementation
    }
    
    generateForm() {
        // Implementation
    }
}

4.8.2 Project: Interactive Todo List

class TodoList {
    constructor(container) {
        this.container = container;
        this.tasks = [];
        this.setupEventListeners();
    }
    
    addTask(text) {
        // Implementation
    }
    
    removeTask(id) {
        // Implementation
    }
    
    toggleTask(id) {
        // Implementation
    }
}

4.9 Performance Optimization

  • Minimizing DOM access

  • Document fragments

  • Event delegation

  • Reflow dan repaint considerations

  • Memory leak prevention

4.10 Best Practices

  • Caching DOM queries

  • Using appropriate selectors

  • Event delegation for dynamic elements

  • Clean up event listeners

  • Error handling

4.11 Ringkasan

  • DOM fundamentals

  • Selection dan manipulation methods

  • Event handling

  • Common patterns dan solutions

4.12 Latihan Akhir Bab

  1. Create a dynamic navigation menu

  2. Build an image slider

  3. Implement a form validator

  4. Create a drag and drop interface

  5. Build an interactive modal system

coding full

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>DOM Manipulation Examples</title>
    <style>
        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: Arial, sans-serif;
        }

        body {
            padding: 20px;
            background-color: #f0f0f0;
        }

        .container {
            max-width: 800px;
            margin: 0 auto;
            background: white;
            padding: 20px;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0,0,0,0.1);
        }

        section {
            margin-bottom: 30px;
            padding: 20px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }

        h2 {
            margin-bottom: 15px;
            color: #333;
        }

        button {
            padding: 8px 16px;
            margin: 5px;
            background-color: #4CAF50;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
        }

        button:hover {
            background-color: #45a049;
        }

        .demo-element {
            padding: 10px;
            margin: 10px 0;
            background-color: #f8f9fa;
            border: 1px solid #ddd;
        }

        .highlight {
            background-color: yellow;
        }

        .error {
            color: red;
        }

        .success {
            color: green;
        }
        
        #elementCreationDemo {
            min-height: 100px;
            border: 1px dashed #ccc;
            padding: 10px;
            margin-top: 10px;
        }

        .event-demo {
            padding: 20px;
            background-color: #e9ecef;
            text-align: center;
            margin: 10px 0;
            cursor: pointer;
        }

        .form-group {
            margin-bottom: 15px;
        }

        .form-group label {
            display: block;
            margin-bottom: 5px;
        }

        .form-group input {
            width: 100%;
            padding: 8px;
            border: 1px solid #ddd;
            border-radius: 4px;
        }
    </style>
</head>
<body>
    <div class="container">
        <h1>DOM Manipulation Examples</h1>

        <!-- Element Selection Demo -->
        <section id="selectionDemo">
            <h2>Element Selection</h2>
            <div id="myId" class="demo-element">Element with ID</div>
            <div class="myClass demo-element">Element with Class 1</div>
            <div class="myClass demo-element">Element with Class 2</div>
            <button onclick="demonstrateSelectors()">Demonstrate Selectors</button>
        </section>

        <!-- Element Modification Demo -->
        <section id="modificationDemo">
            <h2>Element Modification</h2>
            <div id="modifyContent" class="demo-element">Original Content</div>
            <button onclick="modifyText()">Modify Text</button>
            <button onclick="modifyHTML()">Modify HTML</button>
            <button onclick="modifyAttributes()">Modify Attributes</button>
            <button onclick="modifyStyles()">Modify Styles</button>
        </section>

        <!-- Element Creation Demo -->
        <section>
            <h2>Element Creation</h2>
            <button onclick="createElements()">Create Elements</button>
            <div id="elementCreationDemo"></div>
        </section>

        <!-- Event Handling Demo -->
        <section id="eventDemo">
            <h2>Event Handling</h2>
            <div class="event-demo" id="eventArea">
                Click me! Then try hovering and other events.
            </div>
            <div id="eventLog"></div>
        </section>

        <!-- Form Validation Demo -->
        <section>
            <h2>Form Validation</h2>
            <form id="validationForm" novalidate>
                <div class="form-group">
                    <label for="username">Username:</label>
                    <input type="text" id="username" required>
                </div>
                <div class="form-group">
                    <label for="email">Email:</label>
                    <input type="email" id="email" required>
                </div>
                <button type="submit">Submit</button>
            </form>
        </section>
    </div>

    <script>
        // Element Selection Demo
        function demonstrateSelectors() {
            // By ID
            const elementById = document.getElementById('myId');
            elementById.classList.toggle('highlight');

            // By Class Name
            const elementsByClass = document.getElementsByClassName('myClass');
            Array.from(elementsByClass).forEach(el => {
                el.classList.toggle('highlight');
            });

            // Query Selector
            const element = document.querySelector('.myClass');
            element.style.fontWeight = element.style.fontWeight === 'bold' ? 'normal' : 'bold';
        }

        // Element Modification Demo
        function modifyText() {
            const element = document.getElementById('modifyContent');
            element.textContent = 'Text Modified at: ' + new Date().toLocaleTimeString();
        }

        function modifyHTML() {
            const element = document.getElementById('modifyContent');
            element.innerHTML = '<strong>HTML Modified</strong> with <em>formatting</em>';
        }

        function modifyAttributes() {
            const element = document.getElementById('modifyContent');
            element.setAttribute('data-modified', 'true');
            element.dataset.timestamp = Date.now();
            alert('Attributes added! Check element inspector.');
        }

        function modifyStyles() {
            const element = document.getElementById('modifyContent');
            element.style.backgroundColor = '#' + Math.floor(Math.random()*16777215).toString(16);
            element.style.padding = '20px';
            element.style.borderRadius = '8px';
            element.style.transition = 'all 0.3s ease';
        }

        // Element Creation Demo
        function createElements() {
            const container = document.getElementById('elementCreationDemo');
            container.innerHTML = ''; // Clear previous content

            // Create new element
            const div = document.createElement('div');
            div.className = 'demo-element';
            div.textContent = 'Dynamically created element';

            // Create text node
            const text = document.createTextNode(' - Created at: ' + new Date().toLocaleTimeString());
            div.appendChild(text);

            // Add to DOM
            container.appendChild(div);
        }

        // Event Handling Demo
        const eventArea = document.getElementById('eventArea');
        const eventLog = document.getElementById('eventLog');

        function logEvent(eventType) {
            const log = document.createElement('div');
            log.textContent = `${eventType} at ${new Date().toLocaleTimeString()}`;
            eventLog.prepend(log);
            if (eventLog.children.length > 5) {
                eventLog.removeChild(eventLog.lastChild);
            }
        }

        eventArea.addEventListener('click', (e) => {
            logEvent('Click');
            e.target.style.backgroundColor = '#' + Math.floor(Math.random()*16777215).toString(16);
        });

        eventArea.addEventListener('mouseover', () => logEvent('Mouse Over'));
        eventArea.addEventListener('mouseout', () => logEvent('Mouse Out'));

        // Form Validation Demo
        const form = document.getElementById('validationForm');
        
        form.addEventListener('submit', (e) => {
            e.preventDefault();
            
            const username = document.getElementById('username');
            const email = document.getElementById('email');
            let isValid = true;

            // Username validation
            if (!username.value.trim()) {
                showError(username, 'Username is required');
                isValid = false;
            } else {
                showSuccess(username);
            }

            // Email validation
            const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
            if (!email.value.trim()) {
                showError(email, 'Email is required');
                isValid = false;
            } else if (!emailRegex.test(email.value.trim())) {
                showError(email, 'Please enter a valid email');
                isValid = false;
            } else {
                showSuccess(email);
            }

            if (isValid) {
                alert('Form submitted successfully!');
                form.reset();
            }
        });

        function showError(input, message) {
            const formGroup = input.parentElement;
            formGroup.querySelector('.error-message')?.remove();
            const error = document.createElement('div');
            error.className = 'error-message error';
            error.textContent = message;
            formGroup.appendChild(error);
            input.style.borderColor = 'red';
        }

        function showSuccess(input) {
            const formGroup = input.parentElement;
            formGroup.querySelector('.error-message')?.remove();
            input.style.borderColor = 'green';
        }
    </script>
</body>
</html>

Last updated