skip to Main Content

I am using javascript to populate the HTML inside my todo list, but I am struggling to implement a way of storing the data inbetween refreshes of the webpage. I know I should be using localStorage get/set but I’m unsure how best to implement, any guidance would be much appreciated.

I’ve tried implementing myself but I believe I am making errors in the placement of my functions and keep getting either HTML duplications or app breakage

const submitButton = document.querySelector(".submit-button");
const taskInput = document.querySelector(".todo-input");
const listInput = document.querySelector(".list-input");
const checkboxDelete = document.querySelectorAll(".checkbox");
const deleteButton = document.querySelector(".delete-tasks");

let todoList = JSON.parse(localStorage.getItem("todoList")) || [];

submitButton.addEventListener("click", () => {
  const checkIfhidden = document.querySelector(".todo-list");
  const deleteButton = document.querySelector(".delete-tasks");

  if (taskInput.value === "") {
    window.alert("Please enter a new task before submitting");
  } else {
    addTodo(taskInput.value);

    deleteButton.classList.remove("hidden");

    if (checkIfhidden.classList.contains("hidden")) {
      checkIfhidden.classList.remove("hidden");
    }
  }
});

function addTodo(item) {
  if (item !== "") {
    const todo = {
      id: Date.now(),
      name: item,
      completed: false,
    };
    todoList.push(todo);
    renderTodoList(todo);
    taskInput.value = "";
  }
}

function renderTodoList() {
  const renderedList = document.querySelector(".todo-list");
  renderedList.innerHTML = "";

  todoList.forEach((todo) => {
    const newListItem = document.createElement("div");
    newListItem.classList.add("list-item");

    newListItem.innerHTML = `
  <label for="item-${todo.id}">${todo.name}</label>
                 <input type="checkbox" class="checkbox" data-delete-id="${todo.id}">`;

    renderedList.appendChild(newListItem);
  });

  saveToStorage();
}

deleteButton.addEventListener("click", () => {
  const checkboxes = document.querySelectorAll(".checkbox:checked");
  checkboxes.forEach((checkbox) => {
    const todoId = parseInt(checkbox.getAttribute("data-delete-id"));
    todoList = todoList.filter((todo) => todo.id !== todoId);
  });

  if (todoList.length < 1) {
    document.querySelector(".todo-list").classList.add("hidden");
    document.querySelector(".delete-tasks").classList.add("hidden");
  }
  renderTodoList();
});

function saveToStorage() {
  localStorage.setItem("todoList", JSON.stringify(todoList));
}
<script src="https://kit.fontawesome.com/bd47ea96a8.js" crossorigin="anonymous"></script>
<div class="card">
  <div class="title">
    <h3>To-Do List</h1>
      <i class="fa-solid fa-list-check"></i>
  </div>
  <div class="list-input">
    <input type="text" class="todo-input
            " placeholder="Add your task">
    <button class="submit-button">Add</button>
  </div>
  <div class="todo-list hidden">

  </div>
  <button class="delete-tasks hidden">Mark as Complete</button>

</div>


<script type="module" src="./todo.js"></script>

3

Answers


  1. Please do mention what code you tried, and what errors you received.

    However, using localStorage is pretty easy. Since your variable todoList is an array of objects, you’ll also have to use stringify and parse functions provided in JSON.

    For storing – use JSON.stringify(object) to convert your todoList variable to a string, and then store it in localStorage (since it does not support object storage).

    localStorage.setItem("todoList", JSON.stringify(todoList));
    

    For retrieving – use JSON.parse(string) to parse the stored string to an object. Also keep a empty array as fallback incase the key ("todoList") is undefined or null.

    let todoList = JSON.parse(localStorage.getItem("todoList")) || [];
    

    Hope this helps!

    Login or Signup to reply.
  2. I do not see any type of error, however, if you are using js only you should be able to get your local storage like this:
    by setting it:
    localstorage.setitem("jwt", jwtCurrent);

    and by obtaining them:

    const value = localStorage.getItem(key);

    You save this in the storage of the browser, so you will be able to find it in its section

    Login or Signup to reply.
  3. You can write some wrapper functions to handle serialization and serialization of your data.

    You can also add options to hint at the type of data that is being stored or retrieved.

    const saveToLocalStorage = (key, value, { isObject = false, isNumber = false } = {}) => {
      let serializedValue;
      if (isObject) {
        serializedValue = JSON.stringify(value);
      } else if (isNumber) {
        serializedValue = value.toString();
      } else {
        serializedValue = value;
      }
      localStorage.setItem(key, serializedValue);
    };
    
    const loadFromLocalStorage = (key, defaultValue, { isObject = false, isNumber = false } = {}) => {
      const existingData = localStorage.getItem(key);
    
      if (existingData === null || existingData === undefined) {
        console.warn(`Value for '${key}' is undefined or not found!`);
        return defaultValue;
      }
    
      if (!existingData.trim()) {
        console.warn(`Existing data is blank`);
        return defaultValue;
      }
    
      if (isObject) {
        try {
          return JSON.parse(existingData);
        } catch (e) {
          console.warn(`Could not deserialize existing value: ${e.message}`);
          return defaultValue;
        }
      }
    
      if (isNumber) {
        const numberValue = Number(existingData);
        if (isNaN(numberValue)) {
          console.warn(`Stored value is not a valid number`);
          return defaultValue;
        }
        return numberValue;
      }
    
      return existingData;
    };
    

    Usage

    Here is how you would use the saveToLocalStorage and loadFromLocalStorage functions above:

    // Storing and retrieving an object
    const todoList = [
      { id: 1, text: 'Eat breakfast', done: true },
      { id: 2, text: 'Take out the trash', done: false },
      { id: 3, text: 'Go to work', done: false }
    ];
    saveToLocalStorage('todoList', todoList, { isObject: true });
    const todoListCopy = loadFromLocalStorage('todoList', [], { isObject: true });
    console.log(todoListCopy);
    
    // Storing and retrieving a number
    const myNumber = 42;
    saveToLocalStorage('myNumber', myNumber, { isNumber: true });
    const myNumberCopy = loadFromLocalStorage('myNumber', 0, { isNumber: true });
    console.log(myNumberCopy);
    
    // Storing and retrieving a string
    const myString = 'Hello, World!';
    saveToLocalStorage('myString', myString);
    const myStringCopy = loadFromLocalStorage('myString', 'Default String');
    console.log(myStringCopy);
    

    Type inference and decoupling logic

    Instead of a bunch of options to determine how to serialize the data, you can use the typeof operation to infer the type of the data.

    You could also decouple the serialization logic to simply the logic and make it more modular.

    Keep in mind that this only works if you supply a default value, of the correct type.

    const serialize = (value) => {
      switch (typeof value) {
        case 'object': return JSON.stringify(value);
        case 'number': return value.toString();
        default: return value;
      }
    };
    
    const deserialize = (value, defaultValue) => {
      switch (typeof defaultValue) {
        case 'object':
          try {
            return JSON.parse(value);
          } catch (e) {
            console.warn(`Could not deserialize existing value: ${e.message}`);
            return defaultValue;
          }
        case 'number':
          const numberValue = Number(value);
          if (isNaN(numberValue)) {
            console.warn(`Stored value is not a valid number`);
            return defaultValue;
          }
          return numberValue;
        case 'string':
        default:
          return value;
      }
    };
    

    Here are the updated functions:

    const saveToLocalStorage = (key, value) => {
      localStorage.setItem(key, serialize(value));
    };
    
    const loadFromLocalStorage = (key, defaultValue) => {
      const existingData = localStorage.getItem(key);
    
      if (existingData === null || existingData === undefined) {
        console.warn(`Value for '${key}' is undefined or not found!`);
        return defaultValue;
      }
    
      if (!existingData.trim()) {
        console.warn(`Existing data is blank`);
        return defaultValue;
      }
    
      return deserialize(existingData, defaultValue);
    };
    

    And finally the modified usage:

    // Storing and retrieving an object
    const todoList = [
      { id: 1, text: 'Eat breakfast', done: true },
      { id: 2, text: 'Take out the trash', done: false },
      { id: 3, text: 'Go to work', done: false }
    ];
    saveToLocalStorage('todoList', todoList);
    const todoListCopy = loadFromLocalStorage('todoList', []);
    console.log(todoListCopy);
    
    // Storing and retrieving a number
    const myNumber = 42;
    saveToLocalStorage('myNumber', myNumber);
    const myNumberCopy = loadFromLocalStorage('myNumber', 0);
    console.log(myNumberCopy);
    
    // Storing and retrieving a string
    const myString = 'Hello, World!';
    saveToLocalStorage('myString', myString);
    const myStringCopy = loadFromLocalStorage('myString', 'Default String');
    console.log(myStringCopy);
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search