Unit 4 - Notes

INT219 6 min read

Unit 4: DOM Manipulation and Modern Tooling

1. Document Object Model (DOM) Structure

The DOM is an interface (API) that treats an HTML or XML document as a tree structure, where each node is an object representing a part of the document.

The Tree Structure

  • Root Node: The top of the tree, typically the document object.
  • Element Nodes: Represents HTML tags (e.g., <body>, <div>, <a>).
  • Text Nodes: Contains the actual text inside an element. Text nodes are leaf nodes (they cannot have children).
  • Attribute Nodes: Represents attributes like class="container" or href.

The window vs. document

  • Window: The global object representing the browser window/tab containing the DOM. It holds global variables and functions (e.g., setTimeout, fetch).
  • Document: A property of the window object (window.document). It is the entry point into the DOM tree.

DOM Hierarchy Visualization

HTML
<!DOCTYPE html>
<html>          <!-- Root Element -->
  <head>        <!-- Child of html -->
    <title>     <!-- Child of head -->
  </head>
  <body>        <!-- Child of html, Sibling of head -->
    <h1>        <!-- Child of body -->
      Hello     <!-- Text Node (Child of h1) -->
    </h1>
  </body>
</html>


2. DOM Traversal and Manipulation

Selecting Elements

Modern selection relies heavily on CSS-style selectors.

  • document.getElementById('id'): Returns a single element (fastest).
  • document.querySelector('.class'): Returns the first matching element.
  • document.querySelectorAll('.class'): Returns a static NodeList of all matching elements.
  • document.getElementsByClassName('class'): Returns a live HTMLCollection (updates automatically if the DOM changes).

Tree Traversal

Moving between nodes relative to a selected element.

  • Parents: element.parentElement
  • Children:
    • element.children (HTMLCollection of element nodes only—preferred).
    • element.childNodes (NodeList including text nodes/whitespace).
  • Siblings:
    • element.nextElementSibling
    • element.previousElementSibling

Creating and Placing Nodes

  1. Create: const div = document.createElement('div');
  2. Add Content: div.textContent = 'New Item';
  3. Append:
    • parent.appendChild(node) (Adds to end).
    • parent.prepend(node) (Adds to start).
    • parent.insertBefore(newNode, referenceNode) (Adds before specific child).
  4. Remove: element.remove() or parent.removeChild(child).

3. Dynamic Styling and Content Updates

Updating Content

  • element.textContent: Gets or sets the text content of a node and its descendants. Safe from XSS attacks.
    • Note: It respects CSS styling (like text-transform), but returns text hidden by CSS.
  • element.innerText: Similar to textContent, but aware of CSS styling (won't return hidden text) and triggers a reflow (slower).
  • element.innerHTML: Parses the content as HTML.
    • Warning: Security risk (Cross-Site Scripting / XSS) if used with user input.

Manipulating Classes (The classList API)

Avoid manipulating the className string directly. Use the classList interface:

  • element.classList.add('active')
  • element.classList.remove('active')
  • element.classList.toggle('active') (Adds if missing, removes if present).
  • element.classList.contains('active') (Returns boolean).

Inline Styles

Directly modifies the style attribute. Properties use camelCase instead of kebab-case.

JAVASCRIPT
const box = document.querySelector('.box');
box.style.backgroundColor = 'blue'; // CSS: background-color
box.style.marginTop = '20px';       // CSS: margin-top

Reading Computed Styles

To read styles defined in external CSS files (not inline), use window.getComputedStyle.

JAVASCRIPT
const styles = getComputedStyle(box);
console.log(styles.fontSize); // Returns actual pixel value


4. Event Propagation and Delegation

Event Flow Phases

When an event occurs (like a click), it travels through the DOM in three phases:

  1. Capturing Phase: The event travels down from the window to the target element.
  2. Target Phase: The event reaches the actual element clicked.
  3. Bubbling Phase: The event bubbles up from the target back to the window.

By default, addEventListener listens during the Bubbling phase.

The Event Object (e or event)

Passed automatically to the callback function.

  • e.target: The actual element that triggered the event.
  • e.currentTarget: The element the event listener is attached to.
  • e.preventDefault(): Stops default browser behavior (e.g., prevents form submission or link navigation).
  • e.stopPropagation(): Stops the event from bubbling further up the tree.

Event Delegation

A performance pattern where a single listener is placed on a parent container to manage events for multiple child elements (even those created dynamically).

Benefits: reduces memory usage (fewer listeners) and handles dynamic content without re-attaching listeners.

Example:

JAVASCRIPT
// BAD: Adding listener to every list item
// listItems.forEach(item => item.addEventListener(...));

// GOOD: Event Delegation on the parent UL
const list = document.querySelector('#todo-list');

list.addEventListener('click', function(e) {
    // Check if the clicked element is a delete button
    if (e.target.classList.contains('delete-btn')) {
        const itemToDelete = e.target.parentElement;
        itemToDelete.remove();
    }
});


5. Debugging Using Browser Developer Tools

Elements Panel

  • Inspect DOM: View the live DOM tree structure.
  • Modify on the fly: Double-click attributes or text to edit. Drag and drop elements to reorder.
  • Styles Pane: View applied CSS rules, toggle specific properties, and view the Box Model (margin/border/padding).
  • Force State: Right-click an element to force states like :hover, :focus, or :active.

Console Panel

  • Logging: console.log, console.warn, console.error, console.table (for arrays/objects).
  • Interaction: Access currently selected element in Elements panel using $0.
  • Preserve Log: Keep logs between page refreshes (checkbox in settings).

Sources Panel (JavaScript Debugging)

  • Breakpoints: Click the line number to pause code execution at that specific line.
  • Watch: Monitor the values of specific variables as code executes.
  • Call Stack: See the path of functions that led to the current execution point.
  • Controls:
    • Resume: Continue until next breakpoint.
    • Step Over: Execute next line (skip function internals).
    • Step Into: Enter the function being called.

Network Panel

  • Monitor HTTP requests (Fetch/XHR).
  • Analyze loading time (Waterfall).
  • Check headers, payload (request body), and preview (response data).

6. Module Bundling Concepts

The Problem with "Old" JavaScript

Historically, JS was loaded via multiple <script> tags. This caused:

  1. Global Scope Pollution: Variables overwriting each other.
  2. Order Dependency: Scripts had to be loaded in a specific order.
  3. HTTP Bottlenecks: Too many separate file requests.

ES Modules (ESM)

Modern JavaScript supports native modules using import and export.

JAVASCRIPT
// mathUtils.js
export const add = (a, b) => a + b;

// main.js
import { add } from './mathUtils.js';
console.log(add(2, 2));

What is a Bundler?

A tool that takes your source code (JS, CSS, Images), creates a dependency graph to understand how modules relate, and outputs optimized files (bundles) for the browser.

Key Tools

  1. Webpack: Highly configurable, industry standard for years. Handles complex asset transformation via "Loaders" and "Plugins."
  2. Vite: Modern, extremely fast build tool. Uses native ES Modules during development for instant start-up and Rollup for production bundling.
  3. Parcel: Zero-configuration bundler.

Transpilation (Babel)

Browsers evolve, but older browsers (like IE11) don't support modern JS syntax (ES6+).

  • Babel: Converts modern JavaScript into backward-compatible versions (e.g., converts const to var, arrow functions to function).
  • Usually integrated into the build process/bundler.

7. Code Linting and Formatting Practices

Linting and formatting are distinct but complementary processes used to maintain code health.

Linting (e.g., ESLint)

Analyzes code for errors and code quality issues. It catches bugs and enforces logic rules.

  • Finds: Syntax errors, unused variables, undefined variables, unreachable code.
  • Enforces: Best practices (e.g., using === instead of ==).
  • Configuration: .eslintrc file defines rules (e.g., "no-console": "warn").

Formatting (e.g., Prettier)

Focuses strictly on style and visual consistency. It does not check logic.

  • Handles: Indentation (tabs vs spaces), line length, semi-colons, quotes (single vs double), spacing around brackets.
  • Goal: Stops arguments about code style in team reviews. "Format on Save" is a common workflow.
  • Configuration: .prettierrc.

Workflow Integration

  1. Editor Extensions: VS Code extensions highlight errors in real-time.
  2. Pre-commit Hooks (Husky): Prevents committing code if it fails linting or isn't formatted.
  3. CI/CD Pipeline: Checks code quality before merging to the main branch.