Session 2.5 – DOM Manipulation
Module 2: JavaScript & AJAX | Duration: 1 hr
Learning Objectives
By the end of this session, students will be able to:
- Understand the Document Object Model (DOM) structure
- Select and access HTML elements using various methods
- Modify element content, attributes, and styles
- Create, append, and remove elements dynamically
- Navigate the DOM tree structure
Introduction to DOM
The Document Object Model (DOM) is a programming interface for HTML documents. It represents the page structure as a tree of objects, allowing JavaScript to access and manipulate the content, structure, and style of a web page.
What is the DOM?
The DOM is not part of JavaScript itself but is a Web API provided by browsers. It creates a logical tree structure from your HTML document, where each element, attribute, and piece of text becomes a node that JavaScript can interact with.
DOM Structure
The DOM represents an HTML document as a tree structure, where each element is a node.
document
└─ html
├─ head
│ ├─ title
│ └─ meta
└─ body
├─ header
│ └─ h1
├─ main
│ ├─ section
│ │ ├─ h2
│ │ └─ p
│ └─ section
└─ footer
// HTML Example: // <div id="container"> // <h1 class="title">Hello World</h1> // <p class="text">This is a paragraph.</p> // </div> // Accessing the document object console.log(document); // The entire document console.log(document.documentElement); // <html> element console.log(document.head); // <head> element console.log(document.body); // <body> element console.log(document.title); // Page title // Document information console.log(document.URL); // Current URL console.log(document.domain); // Domain name console.log(document.lastModified); // Last modification date
Selecting Elements
Classic Selection Methods
// getElementById - returns single element
let element = document.getElementById("myId");
console.log(element);
// getElementsByClassName - returns HTMLCollection (array-like)
let elements = document.getElementsByClassName("myClass");
console.log(elements[0]); // Access first element
// getElementsByTagName - returns HTMLCollection
let paragraphs = document.getElementsByTagName("p");
for (let p of paragraphs) {
console.log(p.textContent);
}
// getElementsByName - returns NodeList
let radioButtons = document.getElementsByName("gender");
console.log(radioButtons);
Modern Selection Methods (Recommended)
// querySelector - returns first matching element
let firstParagraph = document.querySelector("p");
let elementById = document.querySelector("#myId");
let elementByClass = document.querySelector(".myClass");
let complexSelector = document.querySelector("div.container > p.text");
console.log(firstParagraph);
// querySelectorAll - returns NodeList (array-like)
let allParagraphs = document.querySelectorAll("p");
let allDivs = document.querySelectorAll("div");
let specificElements = document.querySelectorAll("div.active, p.highlight");
// Convert to array for array methods
let paragraphArray = Array.from(allParagraphs);
paragraphArray.forEach(p => console.log(p.textContent));
// Or use spread operator
[...allParagraphs].map(p => p.textContent);
// querySelectorAll examples
document.querySelectorAll("div > p"); // Direct children
document.querySelectorAll("div p"); // All descendants
document.querySelectorAll("p:first-child"); // First child p elements
document.querySelectorAll("p:nth-child(2)"); // Second child p elements
document.querySelectorAll("a[target]"); // Links with target attribute
document.querySelectorAll("input[type='text']"); // Text inputs
Modifying Elements
Modifying Content
let element = document.getElementById("myElement");
// textContent - gets/sets text content (no HTML)
console.log(element.textContent);
element.textContent = "New text content";
// innerHTML - gets/sets HTML content (including tags)
console.log(element.innerHTML);
element.innerHTML = "<strong>Bold text</strong>";
// innerText - similar to textContent but respects styling
console.log(element.innerText);
element.innerText = "Visible text only";
// Differences:
let div = document.querySelector("div");
// If div contains: <p>Hello <span style="display:none">World</span></p>
console.log(div.textContent); // "Hello World"
console.log(div.innerText); // "Hello" (World is hidden)
console.log(div.innerHTML); // "<p>Hello <span style="display:none">World</span></p>"
Modifying Attributes
let link = document.querySelector("a");
let image = document.querySelector("img");
// getAttribute() - get attribute value
let href = link.getAttribute("href");
let src = image.getAttribute("src");
// setAttribute() - set attribute value
link.setAttribute("href", "https://example.com");
link.setAttribute("target", "_blank");
image.setAttribute("src", "newimage.jpg");
image.setAttribute("alt", "New image");
// hasAttribute() - check if attribute exists
if (link.hasAttribute("target")) {
console.log("Link has target attribute");
}
// removeAttribute() - remove attribute
link.removeAttribute("target");
// Direct property access (preferred for standard attributes)
link.href = "https://example.com";
link.id = "myLink";
link.className = "nav-link active";
image.src = "image.jpg";
image.alt = "Description";
// data-* attributes
let element = document.querySelector("div");
element.setAttribute("data-user-id", "123");
element.setAttribute("data-role", "admin");
// Access via dataset (camelCase for multi-word attributes)
console.log(element.dataset.userId); // "123"
console.log(element.dataset.role); // "admin"
element.dataset.status = "active";
Modifying Styles
let element = document.getElementById("myElement");
// Inline styles via style property
element.style.color = "blue";
element.style.backgroundColor = "yellow";
element.style.fontSize = "20px";
element.style.padding = "10px";
element.style.border = "2px solid black";
// CSS properties with hyphens use camelCase
element.style.marginTop = "10px";
element.style.borderRadius = "5px";
// Get computed styles (including CSS file styles)
let computedStyle = window.getComputedStyle(element);
console.log(computedStyle.color);
console.log(computedStyle.fontSize);
// cssText - set multiple styles at once
element.style.cssText = "color: red; background: yellow; padding: 10px;";
// Preferred: Use classes instead of inline styles
element.classList.add("highlight");
element.classList.remove("hidden");
element.classList.toggle("active");
element.classList.replace("old-class", "new-class");
// Check if class exists
if (element.classList.contains("active")) {
console.log("Element is active");
}
// className (overwrites all classes)
element.className = "btn btn-primary";
// classList (better - preserves other classes)
element.classList.add("btn", "btn-primary", "btn-lg");
Creating and Removing Elements
Creating New Elements
// createElement - create new element
let newDiv = document.createElement("div");
let newParagraph = document.createElement("p");
let newButton = document.createElement("button");
// Set content and attributes
newDiv.textContent = "This is a new div";
newDiv.id = "newDiv";
newDiv.className = "container";
newParagraph.innerHTML = "This is a <strong>new</strong> paragraph";
newButton.textContent = "Click Me";
newButton.onclick = () => alert("Clicked!");
// createTextNode - create text node
let textNode = document.createTextNode("Hello, World!");
// Append to document
document.body.appendChild(newDiv);
newDiv.appendChild(newParagraph);
newDiv.appendChild(newButton);
// insertBefore - insert before specific element
let referenceElement = document.getElementById("reference");
let parent = referenceElement.parentNode;
parent.insertBefore(newDiv, referenceElement);
// insertAdjacentHTML - insert HTML at specific position
element.insertAdjacentHTML("beforebegin", "<p>Before</p>");
element.insertAdjacentHTML("afterbegin", "<p>First child</p>");
element.insertAdjacentHTML("beforeend", "<p>Last child</p>");
element.insertAdjacentHTML("afterend", "<p>After</p>");
// insertAdjacentElement - insert element at specific position
let newElement = document.createElement("div");
element.insertAdjacentElement("afterend", newElement);
// append() and prepend() - modern methods (can take multiple nodes/strings)
parent.append(newDiv, "Some text", newParagraph);
parent.prepend(newButton);
Removing Elements
let element = document.getElementById("myElement");
// remove() - modern way
element.remove();
// removeChild() - older way
let parent = element.parentNode;
parent.removeChild(element);
// Remove all children
let container = document.getElementById("container");
while (container.firstChild) {
container.removeChild(container.firstChild);
}
// Or simply:
container.innerHTML = "";
// Replace element
let oldElement = document.getElementById("old");
let newElement = document.createElement("div");
newElement.textContent = "New element";
oldElement.replaceWith(newElement);
// Or older way:
let parent = oldElement.parentNode;
parent.replaceChild(newElement, oldElement);
Cloning Elements
let original = document.getElementById("original");
// Clone without children (shallow clone)
let shallowClone = original.cloneNode(false);
// Clone with all children (deep clone)
let deepClone = original.cloneNode(true);
// Append clones
document.body.appendChild(shallowClone);
document.body.appendChild(deepClone);
// Useful for templates
let template = document.getElementById("item-template");
let newItem = template.cloneNode(true);
newItem.id = "item-" + Date.now();
newItem.querySelector(".item-name").textContent = "New Item";
document.getElementById("item-list").appendChild(newItem);
DOM Traversal
Navigate between elements in the DOM tree using parent, child, and sibling relationships.
let element = document.getElementById("myElement");
// Parent relationships
console.log(element.parentNode); // Parent node
console.log(element.parentElement); // Parent element
console.log(element.closest(".container")); // Closest ancestor with class
// Child relationships
console.log(element.childNodes); // All child nodes (including text)
console.log(element.children); // Only element children
console.log(element.firstChild); // First child node
console.log(element.firstElementChild); // First child element
console.log(element.lastChild); // Last child node
console.log(element.lastElementChild); // Last child element
console.log(element.hasChildNodes()); // Check if has children
console.log(element.childElementCount); // Number of child elements
// Sibling relationships
console.log(element.nextSibling); // Next node
console.log(element.nextElementSibling); // Next element
console.log(element.previousSibling); // Previous node
console.log(element.previousElementSibling);// Previous element
// Practical traversal example
function getAllSiblings(element) {
let siblings = [];
let sibling = element.parentNode.firstChild;
while (sibling) {
if (sibling.nodeType === 1 && sibling !== element) {
siblings.push(sibling);
}
sibling = sibling.nextSibling;
}
return siblings;
}
// Get all parents up to body
function getParents(element) {
let parents = [];
let parent = element.parentElement;
while (parent) {
parents.push(parent);
parent = parent.parentElement;
}
return parents;
}
Practical Examples
Example 1: Dynamic Table Generator
// Generate HTML table dynamically
function generateTable(rows, cols) {
let table = document.createElement("table");
table.className = "table table-bordered";
// Create thead
let thead = document.createElement("thead");
let headerRow = document.createElement("tr");
for (let i = 0; i < cols; i++) {
let th = document.createElement("th");
th.textContent = `Column ${i + 1}`;
headerRow.appendChild(th);
}
thead.appendChild(headerRow);
table.appendChild(thead);
// Create tbody
let tbody = document.createElement("tbody");
for (let i = 0; i < rows; i++) {
let row = document.createElement("tr");
for (let j = 0; j < cols; j++) {
let cell = document.createElement("td");
cell.textContent = `Cell ${i + 1}-${j + 1}`;
row.appendChild(cell);
}
tbody.appendChild(row);
}
table.appendChild(tbody);
return table;
}
// Usage
document.getElementById("generateTableBtn").addEventListener("click", () => {
let container = document.getElementById("tableContainer");
container.innerHTML = ""; // Clear previous table
let table = generateTable(5, 4);
container.appendChild(table);
});
Example 2: Image Gallery with Modal
// HTML:
// <div id="gallery"></div>
// <div id="modal" class="modal">
// <span class="close">×</span>
// <img id="modalImage" src="">
// </div>
let images = [
"image1.jpg",
"image2.jpg",
"image3.jpg",
"image4.jpg"
];
let gallery = document.getElementById("gallery");
// Create gallery items
images.forEach((src, index) => {
let imgContainer = document.createElement("div");
imgContainer.className = "gallery-item";
let img = document.createElement("img");
img.src = src;
img.alt = `Image ${index + 1}`;
img.style.width = "200px";
img.style.margin = "10px";
img.style.cursor = "pointer";
// Click to open modal
img.addEventListener("click", () => {
document.getElementById("modal").style.display = "block";
document.getElementById("modalImage").src = src;
});
imgContainer.appendChild(img);
gallery.appendChild(imgContainer);
});
// Close modal
document.querySelector(".close").addEventListener("click", () => {
document.getElementById("modal").style.display = "none";
});
Example 3: Accordion Component
// Create an accordion component
function createAccordion(data) {
let accordion = document.createElement("div");
accordion.className = "accordion";
data.forEach((item, index) => {
// Create accordion item
let accordionItem = document.createElement("div");
accordionItem.className = "accordion-item";
// Create header
let header = document.createElement("div");
header.className = "accordion-header";
header.textContent = item.title;
header.style.padding = "10px";
header.style.backgroundColor = "#f1f1f1";
header.style.cursor = "pointer";
header.style.borderBottom = "1px solid #ddd";
// Create content
let content = document.createElement("div");
content.className = "accordion-content";
content.textContent = item.content;
content.style.padding = "10px";
content.style.display = "none";
// Toggle on header click
header.addEventListener("click", () => {
let isOpen = content.style.display === "block";
content.style.display = isOpen ? "none" : "block";
header.style.backgroundColor = isOpen ? "#f1f1f1" : "#ddd";
});
accordionItem.appendChild(header);
accordionItem.appendChild(content);
accordion.appendChild(accordionItem);
});
return accordion;
}
// Usage
let accordionData = [
{ title: "Section 1", content: "Content for section 1" },
{ title: "Section 2", content: "Content for section 2" },
{ title: "Section 3", content: "Content for section 3" }
];
let myAccordion = createAccordion(accordionData);
document.body.appendChild(myAccordion);
Example 4: Filter List
// HTML:
// <input type="text" id="searchInput" placeholder="Search...">
// <ul id="itemList">
// <li>Apple</li>
// <li>Banana</li>
// <li>Orange</li>
// </ul>
let searchInput = document.getElementById("searchInput");
let itemList = document.getElementById("itemList");
searchInput.addEventListener("input", (e) => {
let searchTerm = e.target.value.toLowerCase();
let items = itemList.getElementsByTagName("li");
Array.from(items).forEach(item => {
let text = item.textContent.toLowerCase();
if (text.includes(searchTerm)) {
item.style.display = "";
} else {
item.style.display = "none";
}
});
});
Session Summary
Key Points
- The DOM represents HTML as a tree structure of nodes
- querySelector() and querySelectorAll() are modern, flexible selection methods
- textContent for text, innerHTML for HTML content, and style for CSS properties
- classList provides a clean way to manage CSS classes
- createElement(), appendChild(), and remove() for dynamic content
- DOM traversal methods navigate parent-child-sibling relationships
- cloneNode() duplicates elements for templates and reuse
- Always manipulate the DOM efficiently to avoid performance issues
Next Session Preview
In the next session, we will explore Client-Side Form Validation, learning how to validate user input before submission using JavaScript.