I am making a to-do list app using basic javascript. I am having a problem with saving the checking status of the checkbox input element and rendering it back when the page is refreshed… I am currently learning javascript, so my whole approach to the checkboxes might need to be changed so tell me about the best method to do so.
here’s the code:
let toDoListArray = JSON.parse(localStorage.getItem("items")) || {
toDoListArray: [
{
inputValue: "wash the dishes",
dateValue: "1-1-2023",
check: false,
},
{
inputValue: "checked example 2",
dateValue: "22-3-2025",
check: true,
},
],
};
addItem();
// the code i used for the checkboxes
let list = [];
document.querySelectorAll("input[type=checkbox]").forEach((element) => {
list.push(element);
let idx = list.indexOf(element);
if (toDoListArray[idx].check) {
element.setAttribute("checked", true);
} else if (!toDoListArray[idx].check) {
element.removeAttribute("checked");
}
element.addEventListener("change", () => {
if (element.checked) {
toDoListArray[idx].check = true;
} else {
toDoListArray[idx].check = false;
}
});
});
//end of checkboxes code
function addItem() {
let savedText = document.querySelector(".task-input");
let inputValue = savedText.value;
let savedDate = document.querySelector(".date-input");
let dateValue = savedDate.value;
let check = false;
if (inputValue) {
toDoListArray.push({
inputValue,
dateValue,
check,
});
}
addItemHTML();
savedText.value = "";
savedDate.value = "";
}
function deleteItem(index) {
toDoListArray.splice(index, 1);
addItemHTML();
}
function addItemHTML() {
let addedHTML = "";
for (let i = 0; i < toDoListArray.length; i++) {
let { inputValue, dateValue } = toDoListArray[i];
addedHTML += `
<div class="rendered-list-item">
<input id="check${i}" type="checkbox">
<label for="check${i}">${inputValue}</label>
<div>${dateValue}</div>
<button class="delete" onclick="deleteItem(${i})") >Delete</button>
</div>
`;
}
let jsonString = JSON.stringify(toDoListArray);
localStorage.setItem("items", jsonString);
document.querySelector(".list").innerHTML = addedHTML;
}
* {
margin: 0 auto;
padding: 0;
box-sizing: border-box;
font-family: sans-serif;
}
html {
scroll-behavior: smooth;
}
:root {
--form-hue: 226;
--form-saturation: 53%;
--form-light: 90%;
--form-bg-color: hsl(
var(--form-hue),
var(--form-saturation),
var(--form-light)
);
--header-bg-color: rgba(147, 147, 147, 0.6);
--header-color: aliceblue;
--list-bg-color: rgba(201, 199, 223, 0.3);
--main-bg-color: hsl(221, 70%, 95%);
--add-color: white;
}
body::-webkit-scrollbar {
width: 0.25rem;
}
body::-webkit-scrollbar-track {
background: #c9c9d7;
}
body::-webkit-scrollbar-thumb {
background: rgb(61, 61, 169);
}
main {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
background-color: var(--main-bg-color);
width: 60%;
height: 100%;
padding: 20px;
}
.header,
.form,
.list {
width: 100%;
padding: 10px;
margin: 10px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
}
.header {
border-radius: 10px;
background-color: var(--header-bg-color);
color: var(--header-color);
font-weight: bold;
}
.form {
background-color: var(--form-bg-color);
border-radius: 10px;
}
.list {
background-color: var(--list-bg-color);
border-radius: 5px;
flex-direction: column;
width: 100%;
}
.task-input,
.date-input,
.add {
border-radius: 10px;
padding: 7px;
margin: 5px;
border: none;
outline: none;
}
.add {
background-color: hsl(
var(--form-hue),
var(--form-saturation),
calc(var(--form-light) * 0.5)
);
color: var(--add-color);
transition: 0.2s;
}
.add:hover {
background-color: hsl(0, 0%, 71%);
scale: 1.07;
font-weight: bold;
cursor: pointer;
}
.add:active {
background-color: aliceblue;
}
.task-input:focus,
.date-input:focus {
background-color: hsl(240, 33%, 95%);
}
.task-input:hover,
.date-input:hover {
outline: 2px solid rgba(62, 93, 152, 0.6);
}
@media only screen and (max-width: 600px) {
main {
width: 100%;
}
}
.rendered-list-item {
display: flex;
justify-content: space-between;
align-items: center;
flex-direction: row;
background-color: hsl(0, 100%, 100%);
border-radius: 10px;
padding: 5px;
margin: 5px;
width: 95%;
flex-wrap: wrap;
}
.list .rendered-list-item:nth-child(even) {
background-color: hsla(222, 32%, 88%, 0.824);
}
.list .rendered-list-item:nth-child(even) div:nth-child(3) {
color: hsla(224, 43%, 72%, 0.824);
}
.rendered-list-item:hover {
background-color: hsla(0, 0%, 100%, 0.824);
}
.rendered-list-item label,
div,
button {
padding: 10px;
border-radius: 10px;
border: none;
}
.rendered-list-item button {
align-self: normal;
transition: 0.2s;
margin-right: 5px;
color: hsl(0, 0%, 71%);
}
.rendered-list-item button:hover {
scale: 1.08;
background-color: hsl(0, 65%, 55%);
color: white;
cursor: pointer;
}
.rendered-list-item div:nth-child(3) {
color: hsl(0, 0%, 71%);
}
.rendered-list-item label:nth-child(2) {
background-color: hsl(233, 100%, 98%);
margin-left: 5px;
flex: 1;
transition: 0.5s;
}
.rendered-list-item input[type="checkbox"]:checked + label {
font-weight: bold;
text-decoration: line-through;
color: hsl(0, 0%, 71%);
}
.rendered-list-item input[type="checkbox"] {
align-self: normal;
margin-left: 5px;
opacity: 0.6;
accent-color: hsl(262, 25%, 56%);
width: 0.9rem;
}
<!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>vanilla javascipt ToDoList</title>
</head>
<body>
<main>
<p class="header">To-Do-List</p>
<div class="form">
<input placeholder="type the task" type="text" class="task-input" />
<input type="date" class="date-input" />
<button class="add" onclick="addItem()">Add</button>
</div>
<div class="list"></div>
</main>
</body>
</html>
as u can see, I tried iterating through the checkboxes to add a "checked" attribute to the ones with the index that corresponds with the saved to-do-list array index and also add an event listener to each element to see if they are checked and change their corresponding to-do list object’s check property, but when the page is reloaded the array’s check property returns back to false and no checked attributes are rendered. when I console log the to-do list array after the event listener and I check the checkbox, the array’s check attribute gets updated to true but once I refresh the page, it becomes false again.
2
Answers
It seems to me you’re not logging the change to localStorage when you click the checkbox.
This event changes the checked state but there’s nothing that triggers your
localStorage.setItem
which is only found in theaddItemHTML
.There are two issues with your code:
As per your code
toDoListArray
should look something like this:But, in the beginning, you are trying to set
toDoListArray
asJSON.parse(localStorage.getItem("items"))
which follows the above array format.And because you using logical OR operator
||
ifJSON.parse(localStorage.getItem("items"))
isfalse
(null
) then we will set thetoDoListArray
asNow if you see both values of
toDoListArray
are diffrent as one is a object and other is an array.You might have not noticed this as you already have the correct array format save in the
localStorage
.To fix this we can just this:
The second issue is what you have mentioned, that the check and unchecked state of the checkbox is not persistent on reload.
The reason for this is that on change of the checkbox state, you also need to update it in the
localStorage
. Like this:Final Code: