JavaScriptLesson 10 of 10Jump to practice
Events and a to-do app
Run code when people click, type and submit forms, then put it all together in a small to-do app.
An event is something that happens on the page: a click, a key press, a form being sent. You tell the browser which function to run when it happens.
element.addEventListener("click", handleClick);
Note: pass handleClick without brackets. You’re handing over the function to call later, not calling it now.
Common events
| Event | Fires when |
|---|---|
click |
The element is clicked or tapped |
input |
The value of a field changes |
submit |
A form is sent |
keydown |
A key is pressed |
change |
A checkbox, select or field is changed and left |
The event object
Your function receives an event object with details about what happened. event.target is the element involved.
<label for="bio">Short bio (max 100 characters)</label><br>
<textarea id="bio" rows="3" cols="40" maxlength="100"></textarea>
<p id="count">0 / 100</p>
<script>
const bio = document.querySelector("#bio");
const count = document.querySelector("#count");
bio.addEventListener("input", (event) => {
const length = event.target.value.length;
count.textContent = length + " / 100";
count.style.color = length > 90 ? "crimson" : "black";
});
</script>Forms and preventDefault
By default, sending a form reloads the page. event.preventDefault() stops that, so your JavaScript can handle the data instead.
Putting it all together: a to-do app
This small app uses almost everything from the JavaScript course: variables, arrays, objects, functions, loops, conditions, the DOM and events. Read through it, run it, then try the challenges below.
<!DOCTYPE html>
<html>
<head>
<style>
body { font-family: sans-serif; max-width: 420px; padding: 8px; }
form { display: flex; gap: 8px; }
input { flex: 1; padding: 8px; font-size: 16px; }
button { padding: 8px 12px; font-size: 16px; cursor: pointer; }
ul { list-style: none; padding: 0; }
li { display: flex; align-items: center; gap: 8px; padding: 8px 0; border-bottom: 1px solid #ddd; }
li span { flex: 1; cursor: pointer; }
li.done span { text-decoration: line-through; color: #999; }
</style>
</head>
<body>
<h2>My tasks</h2>
<form id="new-task">
<label for="task" hidden>New task</label>
<input id="task" placeholder="What needs doing?" autocomplete="off" required>
<button type="submit">Add</button>
</form>
<ul id="tasks"></ul>
<p id="summary"></p>
<script>
const tasks = [
{ text: "Finish the HTML course", done: true },
{ text: "Practice flexbox", done: false },
];
const list = document.querySelector("#tasks");
const summary = document.querySelector("#summary");
function render() {
list.replaceChildren();
tasks.forEach((task, index) => {
const item = document.createElement("li");
if (task.done) item.classList.add("done");
const label = document.createElement("span");
label.textContent = task.text;
label.addEventListener("click", () => {
task.done = !task.done;
render();
});
const remove = document.createElement("button");
remove.textContent = "Delete";
remove.addEventListener("click", () => {
tasks.splice(index, 1);
render();
});
item.append(label, remove);
list.append(item);
});
const left = tasks.filter((t) => !t.done).length;
summary.textContent = left === 0 ? "All done!" : left + " left to do";
}
document.querySelector("#new-task").addEventListener("submit", (event) => {
event.preventDefault();
const input = document.querySelector("#task");
tasks.push({ text: input.value.trim(), done: false });
input.value = "";
render();
});
render();
</script>
</body>
</html>Click a task to tick it off. The key idea is in render(): the data (the tasks array) is the single source of truth, and the page is redrawn from it after every change. Modern frameworks like React are built around this same idea.
Challenges
- Add a Clear completed button that removes every finished task. Hint:
filter. - Show a different message when the list is empty.
- Save the tasks so they survive a page refresh. Look up
localStorageandJSON.stringify. It won’t work inside this sandboxed example, so try it in a file on your own computer.
Practice
Check what you just learned. Fill in the missing code, then answer the quiz.
Exercise 1Solved
Run
sayHiwhen the button is clicked.button.("click", sayHi);Exercise 2Solved
Name the event that fires every time the text in a field changes.
field.addEventListener("", updateCount);Exercise 3Solved
Stop the browser from sending the form and reloading the page.
form.addEventListener("submit", (event) => { event.(); });
Finish the practice to complete this lesson.
Sign in to keep your progress on any device.
