skip to Main Content

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


  1. It seems to me you’re not logging the change to localStorage when you click the checkbox.

    element.addEventListener("change", () => {
          if (element.checked) {
            toDoListArray[idx].check = true;
          } else {
            toDoListArray[idx].check = false;
          }
        });
    

    This event changes the checked state but there’s nothing that triggers your localStorage.setItem which is only found in the addItemHTML.

    Login or Signup to reply.
  2. There are two issues with your code:

    1. As per your code toDoListArray should look something like this:

      [
        {
          inputValue: "wash the dishes",
          dateValue: "1-1-2023",
          check: false,
        },
        {
          inputValue: "checked example 2",
          dateValue: "22-3-2025",
          check: true,
        },
      ]
      

      But, in the beginning, you are trying to set toDoListArray as JSON.parse(localStorage.getItem("items")) which follows the above array format.

      And because you using logical OR operator || if JSON.parse(localStorage.getItem("items")) is false (null) then we will set the toDoListArray as

      {
        toDoListArray: [
          {
            inputValue: "wash the dishes",
            dateValue: "1-1-2023",
            check: false,
          },
          {
            inputValue: "checked example 2",
            dateValue: "22-3-2025",
            check: true,
          },
        ],
      }
      

      Now 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:

      let toDoListArray = JSON.parse(localStorage.getItem("items")) || [
        {
          inputValue: "wash the dishes",
          dateValue: "1-1-2023",
          check: false,
        },
        {
          inputValue: "checked example 2",
          dateValue: "22-3-2025",
          check: true,
        },
      ];
      

    1. 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:

      element.addEventListener("change", () => {
        if (element.checked) {
          toDoListArray[idx].check = true;
        } else {
          toDoListArray[idx].check = false;
        }
      
        localStorage.setItem("items", JSON.stringify(toDoListArray));
      });
      

    Final Code:

    let toDoListArray = JSON.parse(localStorage.getItem("items")) || [{
        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;
        }
    
        localStorage.setItem("items", JSON.stringify(toDoListArray));
      });
    });
    
    //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>
        `;
      }
    
      localStorage.setItem("items", JSON.stringify(toDoListArray));
    
      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>
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search