Project final - To-do DOM
Finalize the to-do app and make the UI and interactions work.
Project wrap-up: the last feature
The app can now add, complete, and delete tasks. As a final feature we'll add a "Complete all" button: when clicked, it marks every task with the done class.
We'll create a new button and append it to the app container. In the click listener we'll loop over list.children with a for...of loop and call classList.add("done") on each item.
list.children is a live collection; every task added to the list shows up here automatically.
Iterating with for...of
list.children returns an HTMLCollection; with a for...of loop we take each child in turn. Writing for (const item of list.children) makes item the next li on each pass.
For each item we call item.classList.add("done"). Unlike toggle, add adds the class if missing and does nothing if already there.
We'll define this button separately from addButton, as completeAllButton.
Exercise Add the complete-all button
Continue on top of the previous lesson's solution. Create a new button, set its textContent to "Complete all", and append it to app. In a click listener, loop with for (const item of list.children) and call item.classList.add("done") on each item.
Show example solution
Write const completeAllButton = document.createElement('button'), set textContent, and append with app.appendChild. Then add completeAllButton.addEventListener('click', function() { for (const item of list.children) { item.classList.add('done'); } }).
Example solution:
// Todo application
const app = document.getElementById("app");
const title = document.createElement("h1");
title.textContent = "Todo list";
app.appendChild(title);
const input = document.createElement("input");
input.placeholder = "New task";
const addButton = document.createElement("button");
addButton.textContent = "Add";
const list = document.createElement("ul");
app.appendChild(input);
app.appendChild(addButton);
app.appendChild(list);
function addTask() {
const text = input.value;
if (text === "") return;
const item = document.createElement("li");
item.textContent = text;
list.appendChild(item);
input.value = "";
}
addButton.addEventListener("click", addTask);
list.addEventListener("click", function(event) {
const target = event.target;
if (target.tagName === "LI") {
target.classList.toggle("done");
}
});
list.addEventListener("dblclick", function(event) {
const target = event.target;
if (target.tagName === "LI") {
list.removeChild(target);
}
});
const completeAllButton = document.createElement("button");
completeAllButton.textContent = "Complete all";
app.appendChild(completeAllButton);
completeAllButton.addEventListener("click", function() {
for (const item of list.children) {
item.classList.add("done");
}
});
Test yourself
-
What do we use to complete all tasks?
for (const item of list.children) { item.classList.add("done"); }- forEach on list
- for...of on list.children
- while on list.firstChild
- map on list.children
Show answer
for...of on list.children — Correct! for...of iterates the live children collection.
-
Complete the for...of loop
for (const item ____) { item.classList.add("done"); }Show answer
for (const item of list.children) { item.classList.add("done"); } -
Match lesson to feature
- Lesson 1
- Heading skeleton
- Lesson 2
- Input, button, list
- Lesson 3
- Adding tasks
- Lesson 4
- Complete and delete
- Lesson 5
- Complete all