Home > Net >  How to make application remember To-do data
How to make application remember To-do data

Time:08-25

I have looked about for quite a while now, and nothing seems to work or fit my current problem.

I am creating a To-Do project and I want chrome to remember your To-Dos, even if you refresh the browser.

I have tried a few methods, but this is where I am at the moment. The javascript updates the localstorage everytime the 'createPost' function is called, and then it is loaded by the code at the bottom (i flagged the relavant lines).

View the updated demo here: https://dominicody.netlify.app/todo/ ( the main website isnt finished so dont judge please lol)

let form = document.getElementById("todo-form");
let input = document.getElementById("input");
let msg = document.getElementById("msg");
let todos = document.getElementById("todos");
let right = document.getElementById("right")
let noToDo = document.getElementById("notodo")
let counter = 0; /* new line */

form.addEventListener("submit", e => {
  e.preventDefault();
  console.log("button clicked");

  formValidation();
});

let formValidation = () => {
  if (input.value === "") {
    msg.innerHTML = "To-Do cannot be blank";
  } else {
    msg.innerHTML = "";
    acceptData();
  }
};

let data = [];

let acceptData = () => {
  data = [...data, {
    "text": input.value
  }];
  input.value = "";
  localStorage.setItem('todoItemsRef', JSON.stringify(data));
  createToDo(data[data.length - 1]);
};

let createToDo = () => {
  counter  ; /* new line */
  todos.innerHTML  = `
    <div>
      <p>${data.text}</p>
      <span >
        <i onClick="completedToDo(this)" class='bx bx-check-circle'></i>
        <i onClick="editToDo(this)" class='bx bx-edit-alt'></i>
        <i onClick="deleteToDo(this)" class='bx bx-trash' ></i>
      </span>
    </div>
    `;
  input.value = "";
};


let completedToDo = (e) => {
  e.parentElement.parentElement.classList.toggle('completed')
}

let deleteToDo = (e) => {
  e.parentElement.parentElement.remove();

  counter--;
  if (counter === 0) {
    showNoToDo();
  }
};

let editToDo = (e) => {
  input.value = e.parentElement.previousElementSibling.innerHTML;
  e.parentElement.parentElement.remove();
};

let hideNoToDo = () => {
  noToDo.classList.add('hidden')
  form.classList.remove('form-reg-position')
}

let showNoToDo = () => {
  noToDo.classList.remove('hidden')
  form.classList.add('form-reg-position')
}

/*     localStorage.setItem('todoItemsRef', JSON.stringify(data)); */
document.addEventListener('DOMContentLoaded', () => {
  const ref = localStorage.getItem('todoItemsRef');
  if (ref) {
    data = JSON.parse(ref);
    data.forEach(t => {
      createToDo(t);
    });
  }
});
@import url('https://fonts.googleapis.com/css2?family=Kanit:wght@100;200;300;400;500;600;700;800;900&family=League Spartan:wght@200;300;400;500;600;700;800;900&family=Noto Serif:wght@400;700&display=swap');
:root {
  --primary-color: rgb(240, 69, 114);
  --primary-color-ligh: rgb(220, 100, 124);
  --secondary-color: rgb(25, 24, 44);
  --secondary-color-ligh: rgb(64, 64, 83);
  --white: rgb(255, 255, 255);
  --primary-font: 'League Spartan', sans-serif;
  --secondary-font: 'Noto Serif', serif;
  --kanit-font: 'Kanit', sans-serif;
  --swiper-theme-color: rgb(240, 69, 114);
}

* {
  padding: 0;
  margin: 0;
  box-sizing: border-box;
  font-family: 'League Spartan', sans-serif;
}

body {
  width: 100%;
  background-color: #fff;
  max-height: 100%;
  overflow: hidden;
}

h1 {
  position: absolute;
  top: 10%;
  left: 50%;
  transform: translateX(-50%);
  font-size: 4rem;
  opacity: 0.5;
}

.todo-main {
  position: absolute;
  top: 30%;
  left: 50%;
  width: 75%;
  height: 70%;
  transform: translateX(-50%);
  overflow-y: auto;
  overflow-x: hidden;
}

.no-todo {
  position: absolute;
  top: 23%;
  left: 50%;
  transform: translateX(-50%);
  text-align: center;
}

.no-todo img {
  width: 150px;
}

.no-todo p {
  font-family: var(--primary-font);
  font-weight: 600;
  font-size: 1.3rem;
  margin-top: 24px;
  margin-bottom: 10px;
}

.no-todo p2 {
  font-family: var(--primary-font);
  font-weight: 600;
  font-size: 1.2rem;
  color: #000;
  opacity: 0.6;
}

.no-todo.hidden {
  display: none;
}

form {
  margin-left: 100%;
  transform: translateX(-50%);
  width: 100%;
  ;
}

.textarea {
  margin-top: 24px;
  min-width: 95%;
  max-width: 95%;
  min-height: 40px;
  max-height: 40px;
  display: flex;
  outline: none;
  border: none;
  border: 2px solid var(--secondary-color);
  border-radius: 5px;
  padding: 10px;
  font-size: 20px;
  font-weight: 400;
  margin-top: 5px;
  color: #000;
  transform: translateX(-50%);
  overflow-y: hidden;
  transition-duration: 0.7s;
}

.form-reg-position {
  transform: translateY(250%) translateX(-50%);
  transition-duration: 0.7s;
}

.textarea::placeholder {
  color: #000;
}

#todos div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  transform: translateX(-50%);
  font-family: var(--kanit-font);
  font-weight: 500;
  font-size: 1.2rem;
  margin-bottom: 15px;
  width: 95%;
  margin-left: 50%;
  border: 2px solid var(--secondary-color);
  border-radius: 5px;
  padding: 8px;
  color: #000;
}

#todos div.completed {
  background-color: #00FF00;
  color: #000;
}

.options {
  display: flex;
  gap: 25px;
  color: var(--secondary-color);
}

i {
  cursor: pointer;
}

#msg {
  position: absolute;
  left: 0%;
  transform: translateX(-50%);
  color: red;
  margin-bottom: 10px;
}


/* TOP NAV */

.top-nav-img-only {
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 8%;
  display: flex;
  align-items: center;
  z-index: 99;
}

.top-nav-img-only a img {
  position: absolute;
  top: 20%;
  left: 5%;
  height: 60%;
}
<!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>bydom</title>

  <link rel="stylesheet" href="/todo/todo.css">
  <link href='https://unpkg.com/[email protected]/css/boxicons.min.css' rel='stylesheet'>
</head>

<body>
  <div >
    <a href="/">
      <img src="/images/logo.png">
    </a>
  </div>
  <h1>todos</h1>
  <div  id="notodo">
    <img src="/svg/checklist.svg">
    <p>Add your first To-Do</p>
    <p2>What's first on your list?</p2>
  </div>
  <div >
    <form  id="todo-form">
      <br><br>
      <input  type="text" name="todo" id="input" placeholder="Add new To-do"></input>
      <br><br>
      <div id="msg"></div>
    </form>
    <div id="todos">

    </div>
  </div>
  <script src="/todo/todo.js"></script>
</body>

</html>

CodePudding user response:

The first thing you need to do is update Local Storage whenever you change something in the tasks.

You can create a function to update Local Storage and this function will be called whenever you update something in the tasks, when you mark it as complete and when you delete a task.

const updateLocalStorage = () => {

}

This function will pick up all the tasks that are on the screen

Add task in Local Storage

localStorage.setItem("tasks", JSON.stringify([...JSON.parse(localStorage.getItem("tasks") || "[]"), { task: task.value, completed: false }]));

CodePudding user response:

There seem to be a few issues with the example/code provided, but the main thing seems to be how you were trying to store the todo list. Your list was an array called data and when each new todo item was created, it would overwrite the previous value of data["text"]. Also, because of the way you structured your array (which was more like an object), you could not stringify the list.

So the first fix was to make your array an array of objects [{},{}]. This would allow each item on the list to have its own text value.

Another issue was calling a function that didn't exist renderTodo. (OP did mention in a comment this was later corrected).

There are also a lot of weird ways some of the code is structured, but with all of that aside, here is a basic example of what you seem to need. I removed functions and code that wasn't necessary for the question asked. This solution will save your todo list in localStorage and load it when the page loads. Anything else is a different question/topic.

let form = document.getElementById("todo-form"),
input = document.getElementById("input"),
msg = document.getElementById("msg"),
todos = document.getElementById("todos"),
data = [];

form.addEventListener("submit", e => {
    e.preventDefault();
    formValidation();
});

let formValidation = () => {
  if (input.value === "") {
    msg.innerHTML = "To-Do cannot be blank";
  } else {
    msg.innerHTML = "";
    acceptData();
  }
};


let acceptData = () => {
  data = [...data, {"text": input.value}];
  input.value = "";
  localStorage.setItem('todoItemsRef', JSON.stringify(data));
  renderTodo(data[data.length-1]);
};

let renderTodo = (t) => {
  let todo = document.createElement("div");
  todo.innerHTML = `<p>${t.text}</p>`;
  todos.append(todo);
};

document.addEventListener('DOMContentLoaded', () => {
  const ref = localStorage.getItem('todoItemsRef');
  if(ref) {
    data = JSON.parse(ref);
    data.forEach(t => {
      renderTodo(t);
    });
  }
});
:root {
    --primary-color: rgb(240, 69, 114);
    --primary-color-ligh: rgb(220, 100, 124);
    --secondary-color: rgb(25, 24, 44);
    --secondary-color-ligh: rgb(64, 64, 83);
    --white: rgb(255, 255, 255);
    --primary-font: 'League Spartan', sans-serif;
    --secondary-font: 'Noto Serif', serif;
    --kanit-font: 'Kanit', sans-serif;
    --swiper-theme-color: rgb(240, 69, 114);
}


* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
    font-family: 'League Spartan', sans-serif;
}

body {
    width: 100%;
    background-color: #fff;
    max-height: 100%;
    overflow: hidden;
}

h1 {
    position: absolute;
    top: 10%;
    left: 50%;
    transform: translateX(-50%);
    font-size: 4rem;
    opacity: 0.5;
}

.todo-main {
    position: absolute;
    top: 30%;
    left: 50%;
    width: 75%;
    height: 70%;
    transform: translateX(-50%);
    overflow-y: auto;
    overflow-x: hidden;
}

.textarea {
  margin-top: 24px;
  min-width: 95%;
  max-width: 95%;
  min-height: 40px;
  max-height: 40px;
  display: flex;
  outline: none;
  border: none;
  border: 2px solid var(--secondary-color);
  border-radius: 5px;
  padding: 10px;
  font-size: 20px;
  font-weight: 400;
  margin-top: 5px;
  color: #000;
  transform: translateX(-50%);
  overflow-y: hidden;
  transition-duration: 0.7s;
}

form {
  margin-left: 100%;
  transform: translateX(-50%);
  width: 100%;
}
#todos div {
  display: flex;
  align-items: center;
  justify-content: space-between;
  transform: translateX(-50%);
  font-family: var(--kanit-font);
  font-weight: 500;
  font-size: 1.2rem;
  margin-bottom: 15px;
  width: 95%;
  margin-left: 50%;
  border: 2px solid var(--secondary-color);
  border-radius: 5px;
  padding: 8px;
  color: #000;
}
<h1>todos</h1>
<div >
  <form  id="todo-form">
    <br><br>
    <input  type="text" name="todo" id="input" placeholder="Add new To-do">
    <br><br>
    <div id="msg"></div>
  </form>
<div id="todos"></div>
</div>

NOTE This example will not run on Stack Overflow because of a lack of access to the localStorage object.

EDIT I also have a relevant CodePen with more of the original code for reference. localStorage will function in this CodePen example.

  • Related