To ask a simple question; Do we need another JavaScript to-do list? I guess it depends on whom it’s for to guess the right answer. A to-do app is generally a beginner’s project in any programming language. If I chuck another one in the mix it may be useful. It is likely to be different from any other. Why is that? My father would say, “There is more than one way to skin a cat”. (Not that he would have, he loved cats). In programming, there are many ways to do things. Whether it’s a different naming convention, organisation of code. We all have our own ways to do things. Anyhow, enough of my ramblings, let’s begin.
Table of contents
A modern browser and a text editor. I recommend VS Code and the Live Server extension. Some knowledge of HTML and JavaScript would be beneficial but not required. I am using a pre-compiled version of the Bulma CSS Framework in this vanilla JavaScript To-do list tutorial.
Also available on GitHub
If you are familiar with a to-do app you may skip to the next section. If you want to see the plan of action then look no more.
Here is our rough pseudocode:
There is a main section of the code. There are 3 functions in total. Add and delete to-dos and a function that saves to localStorage.
First, we will start with the HTML. It’s a pretty basic template using the Bulma CSS framework. In a real-world scenario, it would be more beneficial to use SASS. This would compile what you need or use into 1 CSS file. I have added an input field, a save button and an empty container for the JavaScript to-do list inside the HTML file. It is possible to write them in JavaScript too.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link href="css/bulma.min.css" rel="stylesheet" />
<link href="css/style.css" rel="stylesheet" />
<title>Todo App</title>
</head>
<body>
<section class="section">
<div class="container">
<div id="app">
<h1 class="title">Worldoweb Todo</h1>
<div class="field has-addons">
<div class="control is-expanded">
<input class="input is-medium" id="todoInput" type="text" placeholder="What do you want TODO">
</div>
<div class="control">
<button id="add-btn" class="button is-medium is-primary">Save</button>
</div>
</div>
<div id="todoContainer">
<ul class="list" id="list"></ul>
</div>
</div>
</div>
</section>
<script src="js/global.js"></script>
</body>
</html>
To start with, we will add an event listener to watch the enter key. Once the user presses enter, it will save to localStorage. There is also an event listener attached to the add button.
/**
* Monitors for keyup event
* @param {object} e The event object
*/const keyup = (e) => {
let keyPressed = e.keyCode || e.which;
if (keyPressed === 13) {
addTodo(input.value)
}
};
document.addEventListener('keyup', keyup)
/**
* Attaches an event listener to the button
*/document.getElementById("add-btn").addEventListener("click", () => {
addTodo(input.value);
});
Here comes the 3 functions deleteTodo
addTodo
and saveStorage
/**
* Deletes the todo and saves into local storage
* @param {int} id the id of the todo
*/const deleteTodo = (id) => {
todos.splice(id, 1);
saveStorage(todos);
};
/**
* Adds the todo to local storage
* @param {string} todo_text The text from the input box
*/const addTodo = (todo_text) => {
if (todo_text === '') {
window.alert("Please enter some text")
} else {
let arr = [],
todo = {
value: todo_text,
completed: false,
};
if (todos === null) {
arr.push(todo);
} else {
arr = Object.values(todos);
arr.push(todo);
}
saveStorage(arr);
}
};
/**
* Communicates with the browsers localStorage
* @param {array} todos list of todos
*/const saveStorage = (todos) => {
localStorage.setItem("todos", JSON.stringify(todos));
location.reload();
};
The start of the main section of code is the biggest so I’ll break it up into manageable chunks.
Grab the input object by its ID. This is then passed to the variable input
. The second part grabs the to-dos out of local storage.
/**
* Start of main code
*/
let input = document.getElementById("todoInput");
/**
* Grab the todo list out of storage
*/let todos =
localStorage.getItem("todos") !== null ?
JSON.parse(localStorage.getItem("todos")) :
null;
The next section of the main code will only display the to-dos if there are any in Local Storage.
/**
* Display the todos
*/if (todos !== null) {
for (let i = 0; i < todos.length; i++) {
const del_icon =
'<svg style="width:24px;height:24px" viewBox="0 0 24 24"><path fill="currentColor" d="M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z" /></svg>';
let list = document.getElementById("list"),
li = document.createElement("li"),
classes = ["todo-item", "level"];
li.classList.add(...classes);
li.id = i;
let comp = document.getElementsByClassName("item-value");
li.innerHTML =
'<div class="level-left"><div class="level-item item-value">' +
todos[i].value +
'</div></div><div class="level-right"><div class="level-item"><span class="icon del">' +
del_icon +
"</span></div></div>";
list.appendChild(li);
todos[i].completed === true ? comp[i].classList.toggle("completed") : comp[i].classList.toggle("completed", false);
}
}
The last section of the main code attaches an event listener to every to-do item. As you can see in the last if statement. On pressing the delete icon, the item deletes from LocalStorage. On clicking a to-do item, a line appears through it to show that it’s completed.
/**
* Attaches an event listener to the individual todo items
*/let todoElements = document.getElementsByClassName("todo-item");
for (let i = 0; i < todoElements.length; i++) {
todoElements[i].addEventListener("click", (e) => {
let id = todoElements[i].id,
level_right = todoElements[i].children[1].childNodes[0].firstChild,
level_left = todoElements[i].children[0];
if (e.target === level_right.lastChild) {
deleteTodo(id);
} else if (e.target === level_left.firstChild) {
todos[id].completed === true ? todos[id].completed = false : todos[id].completed = true
saveStorage(todos);
}
});
}
Finally the additional custom CSS
body{
background-color: rgb(235, 237, 243);
height: 100vh;
}
.list{
padding: 1.5rem;
}
.todo-item{
padding: 1rem;
background-color: #fff;
margin: 20px 0;
}
.todo-item .completed {
text-decoration: line-through;
}
As I stated this was a very simple JavaScript to-do list tutorial. Please feel free to fork the code and tweak it further. I will continue to add features to it. Please feel free to request other tutorials.
Welcome to Hot Web Dev October 2024, featuring the latest technology and web development news.… Read More
In this tutorial, you’ll build a fun and interactive guessing game using Svelte 5, the… Read More
Welcome to Hot Web Dev September 2024, featuring the latest technology and web development news.… Read More
The JavaScript guessing game tutorial is a simple beginner's project. It features modern JavaScript syntax… Read More
If you have been following the monthly Hot Web Dev magazine you will find the… Read More
Welcome to Hot Web Dev August 2024, featuring the latest technology and web development news.… Read More