23. Advanced DOM Manipulation & Dynamic Elements
Why Advanced DOM Manipulation Matters
Fetching data from APIs is only useful if you can present it dynamically in the browser. Advanced DOM manipulation allows you to create, update, and remove elements efficiently, handle dynamic datasets, and respond to user interactions in real time.
Creating Elements Dynamically
Use `document.createElement` and `appendChild` to inject data-driven content into the page. This avoids hardcoding elements and allows you to render content from APIs or user input.
const container = document.getElementById('userContainer');
const user = { name: 'Alice', age: 25 };
const card = document.createElement('div');
card.classList.add('user-card');
card.innerHTML = `<h3>${user.name}</h3><p>Age: ${user.age}</p>`;
container.appendChild(card);Updating Elements Based on Data
After fetching data, update existing DOM elements dynamically without reloading the page. This keeps your interface responsive and avoids flickering.
async function updateUserList() {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await res.json();
const list = document.getElementById('userList');
list.innerHTML = '';
users.forEach(user => {
const li = document.createElement('li');
li.textContent = `${user.name} (${user.email})`;
list.appendChild(li);
});
}
updateUserList();Event-Driven Updates
Attach event listeners to respond to user interactions, fetching and rendering data dynamically when needed. This is essential for interactive applications.
document.getElementById('loadUsersBtn').addEventListener('click', async () => {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await res.json();
const list = document.getElementById('userList');
list.innerHTML = '';
users.forEach(user => {
const li = document.createElement('li');
li.textContent = `${user.name} — ${user.email}`;
list.appendChild(li);
});
});Optimizing DOM Updates
For large datasets, use `DocumentFragment` or template literals to minimize reflows and improve performance. Batch DOM changes instead of appending elements one by one.
async function renderUsers() {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
const users = await res.json();
const fragment = document.createDocumentFragment();
users.forEach(user => {
const li = document.createElement('li');
li.textContent = `${user.name} — ${user.email}`;
fragment.appendChild(li);
});
document.getElementById('userList').appendChild(fragment);
}
renderUsers();Handling Loading States and Errors
Always show feedback to users while fetching data. Handle errors gracefully and avoid leaving the interface in a broken state.
async function fetchAndRenderUsers() {
const list = document.getElementById('userList');
list.textContent = 'Loading...';
try {
const res = await fetch('https://jsonplaceholder.typicode.com/users');
if (!res.ok) throw new Error('Failed to fetch users');
const users = await res.json();
list.innerHTML = '';
users.forEach(user => {
const li = document.createElement('li');
li.textContent = `${user.name} — ${user.email}`;
list.appendChild(li);
});
} catch (err) {
list.textContent = `Error: ${err.message}`;
}
}
fetchAndRenderUsers();Mini Challenge
1. Create a search input where users can type a name. 2. Fetch users from an API and display only matching results. 3. Add a loading spinner while fetching. 4. Gracefully handle errors and empty results. 5. Bonus: Highlight the matched text in the results.