DOM Events - Ponder
Activity Instructions
Estimated Time: 60 minutes
Preparation
This activity will walk us through building a simple To-do application that will allow you to add a task, mark a task as completed, and remove a task. It is recommended to review Event Driven Programmming before you start.
You will need your editor open to create a couple of new files for the following code:
html
<!-- events.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Events practice: ToDos</title>
<style>
.todos {
width: 300px;
}
.todos > li {
display: flex;
justify-content: space-between;
align-items: center;
border: 1px solid;
padding: 0.5em;
}
.todos p {
margin: 0;
}
.todos span {
cursor: pointer;
}
.strike {
text-decoration: line-through;
color: gray;
}
</style>
</head>
<body>
<h1>ToDos</h1>
<section>
<label for="todo">Enter Task</label>
<input name="todo" id="todo" />
<button id="submitTask">Enter</button>
</section>
<ul id="todoList" class="todos"></ul>
<script src="events.js"></script>
</body>
</html>
Javascript
// events.js
function newTask() {
// get the list element from the DOM
// get the value entered into the #todo input
// render out the list
listElement.innerHTML += `
<li> ${task}
<div>
<span data-function="delete">❎</span>
<span data-function="complete">✅</span>
</div>
</li>`
}
function manageTasks(e) {
// using the event find the li element closest to what they clicked
const parent = e.target.closest("li");
// did they click the delete or complete icon?
if (e.target.getAttribute('data-function') === "delete") {
parent.remove();
}
if (e.target.getAttribute('data-function') === "complete") {
parent.classList.toggle('strike');
}
}
// Add your event listeners here
// We need to attach listeners to the submit button and the list. Listen for a click, call the 'newTask' function on submit and call the 'manageTasks' function if either of the icons are clicked in the list of tasks.
These activities will be most effective if you TRY them first before you look at the solution. And after you do look at the solution...DO NOT copy and paste the code. Read through it, try to understand what it is doing...then go fix your code.
Activity 1
There are 2 functions to be written, and some events to listen for to complete this simple Todo list application. Begin by reviewing the code you were given. Pay attention to the comments! Also don't forget to check for errors after each step!
- Start with the
newTask
function. Get the value entered in the '#todo' input using the .value property. Then that task is rendered onto the page using the given template literal.`<li> ${task} <div> <span data-function="delete">❎</span> <span data-function="complete">✅</span> </div> </li>`;
- After completing that attach an event listener to the '#submitTask' button that will call the
newTask
function when it is clicked. - After making sure that it is working, complete the
manageTasks
function next. When someone clicks the ❎ it should call theremoveTask()
function. If they click the ✅ then thecompleteTask()
should be called.
One way to approach this would be to attach a listener to each button for each task. But if we up with many tasks that is a lot of listeners to keep track of. Instead we can take advantage of Event Delegation.
If we click on one of the icons the event will 'bubble' up to the list item and look for an event listener there. It will then bubble up to the UL and look for a listener there...so we could simply attach one listener to the parent UL ('#todoList') to catch any click in our list!
One problem though...how do we know which button on which task was clicked? event.currentTarget
always contains a reference to the element the listener is attached to. event.target
always references the element that triggered the event! (the element clicked on in this case)
If you look at the HTML you were provided for a task you will see data-action="delete"
on the delete icon. This is a custom HTML attribute. The data-
is significant, but the action
could have been anything we wanted. We can get the attribute from the element that was clicked and compare it to delete or complete.
Solution 1
function newTask() {
// get the list element
const listElement = document.querySelector('#todoList');
// get the value entered into the #todo input
const task = document.querySelector('#todo').value;
// render out the list
listElement.innerHTML += `
<li> ${task}
<div>
<span data-function="delete">❎</span>
<span data-function="complete">✅</span>
</div>
</li>`;
}
function manageTasks(e) {
console.log(e);
// did they click the delete or complete icon?
const parent = e.target.closest("li");
if (e.target.getAttribute("data-function") === "delete") {
parent.remove();
}
if (e.target.getAttribute("data-function") === "complete") {
parent.classList.toggle("strike");
}
}
// Add your event listeners here for submit button and the to do list
document.querySelector('#submitTask').addEventListener('click', newTask);
document.querySelector('#todoList').addEventListener('click', manageTasks);