I have two problems with my simple to-do app. I've decided to add an option to save your tasks in local Storage and load them next time you visit the app. I've managed to write a function that saves all items by clicking "Zapisz" button in localStorage, but when I reload the page to load them, it cuts 1 or 2 of the items.
Also, I can't figure out how to add appropriate class to saved item (there are two different classes, "item" and "itemDone"). So this is my problem, and here is the JS code:
(function() {
/* Load items from localStorage if there are any */
window.addEventListener("DOMContentLoaded", function() {
var myList = document.getElementById("list");
for (var i = 0; i < localStorage.length; i++) {
var item = document.createElement("li");
localKey = localStorage.getItem(localStorage.key(i));
item.innerHTML = JSON.parse(localKey);
if (item.innerHTML.indexOf("check") != -1) {
item.className = "itemDone";
} else {
item.className = "item";
}
myList.appendChild(item);
var closers = document.getElementsByClassName("closer");
for (var i = 0; i < closers.length; i++) {
closers[i].addEventListener("click", deleteItem);
}
};
});
/* This function deletes parent element of clicked element - in this case a clicked element will be a "span" element with "closer" class, and it's parent is "li" element */
function deleteItem() {
this.parentNode.parentNode.removeChild(this.parentNode);
};
/* this function allows to delete item from the loist */
var x = document.getElementsByClassName("closer"); // get all elements with "closer" class
for (var i = 0; i < x.length; i++) { // simple loop that adds eventListener to all elements with "closer" class
x[i].addEventListener("click", deleteItem); // on click function "deleteItem" is invoked
};
/* This function adds "li" element to the list with text value from input #newInput, and then adds a span with innertext "X" and class .closer */
function addItem() {
var myList = document.getElementById("list"); // get the main list ("ul")
var newListItem = document.createElement("li"); //create a new "li" element
var itemText = document.getElementById("newInput").value; // read the input value from #newInput
var listText = document.createTextNode(itemText); // create text node with calue from input
newListItem.appendChild(listText); // add text node to new "li" element
newListItem.className = ""
if (itemText === "") { // if input value is empty
alert("Pole nie może być puste"); // show this alert
} else { // if it's not empty
var x = document.createElement("span"); // create a new "span" element
x.innerText = "X"; // add inner text to "span" element
x.className = "closer"; // add class to "span" element
x.addEventListener("click", deleteItem, false);
myList.appendChild(newListItem); // add created "li" element to "ul"
newListItem.className = "item"; // add class to new "li" element
newListItem.appendChild(x); // add a "span" to new "li" element
var itemText = document.getElementById("newInput"); // read current input value
itemText.value = ""; // set current input value to null
}
};
/* addButton reffers to the button used to add new elements to the list. After clicking it, function "addItem" is called */
var addButton = document.getElementById("createNew"); // fetch the "createNew" button
addButton.addEventListener("click", addItem); // add click event to "createNew" button and run function
/* This function clears all added elements from the list */
/* This script adds a method in which you can also add a new "li" item with "enter" keydown */
var textAdd = document.getElementById("newInput"); // target input
textAdd.addEventListener ("keypress", function (e) { // add event listener on "keypress"
var key = e.which || e.keyCode; // which key is being used
if (key === 13){ // if pressed key is "enter" (13)
e.preventDefault(); // prevent default "enter" action
addItem(); // addItem function is invoked
};
});
function clearList(){
var myList = document.getElementById("list"); // get the "ul" element
myList.innerHTML = ""; // clear all it's children
window.localStorage.clear();
};
/* deleteAll variable reffers the button used to clear all items. After clicking it, function "deleteAll" is called */
var deleteAll = document.getElementById("deleteAll"); // fetch the "deleteAll" button
deleteAll.addEventListener("click", clearList); // add click event to "deleteAll" button and run finction
/* This code changes the class of clicked "li" element from "item" to "itemDone" using event delegation method */
document.getElementById("list").addEventListener("click", function(e) {
if (e.target && e.target.matches("li.item")) { // if event target matches an "li" item with "item" class
e.target.className = "itemDone"; // change class to "itemDone"
var check = document.createElement("i"); // create new "i" element
check.className = "fa fa-check done"; // add class to "i" element
e.target.appendChild(check); // add new "i" element to event target ("li")
} else if (e.target && e.target.matches("li.itemDone")) {// if event target matches an "li" item with "itemDone" class
e.target.className = "item"; // change class to "item"
var done = e.target.getElementsByClassName("done"); // choose target with "done" class
for (var i = 0; i < done.length; i++) {
e.target.removeChild(done[i]); // remove "i" element with "done" class from target
};
};
});
/* Save all "li" items form the list to localStorage */
var saveAll = document.getElementById("saveAll");
saveAll.addEventListener("click", function() {
var item = document.getElementsByTagName("li");
for (var i = 0; i < item.length; i++) {
localStorage.setItem([i], JSON.stringify(item[i].innerHTML));
};
});
})();
And HTML:
<!DOCTYPE html>
<html lang="pl">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Sansita&subset=latin-ext">
<link rel="stylesheet" href="css/font-awesome.min.css">
<link rel="stylesheet" href="css/main.css">
<title>Prosta aplikacja To-Do list</title>
<meta name="description" content="Prosta aplikacja zadań To-Do">
<meta name="keywords" content="aplikacja, to-do, lista, zadań, javascript">
<meta name="author" content="Michał Grochowski">
</head>
<body>
<header id="header">
<div class="description">
<h1>Prosta aplikacja To-Do</h1>
</div>
</header>
<section>
<div class="mainlist">
<form class="form">
<input id="newInput" type="text" placeholder="Dodaj pozycję">
<button id="createNew" type="button">Dodaj</button>
</form>
<h2>Moja lista:</h2>
<div class="listBg">
<ul id="list">
</ul>
</div>
<div class="flex-row">
<button id="deleteAll" type="button">Wyczyść</button>
<button id="saveAll" type="button">Zapisz</button>
</div>
<p class="helpText">Żeby dodać pozycję do listy wpisz tekst w polu "Dodaj pozycję", a następnie kliknij przycisk "Dodaj" lub wciśnij enter.</p>
<p class="helpText">Kliknij wybrane zadanie, żeby oznaczyć je jako wykonane. W ten sam sposób możesz je odznaczyć.</p>
<p class="helpText">Usuń wybraną pozycję z listy kilkając "X" w prawym rogu.</p>
<p class="helpText">Żeby zapisac listę w pamięci przeglądarki, kliknij przycisk "Zapisz".</p>
<p class="helpText">Żeby wyczyścić całą listę, kliknij przycisk "Wyczyść".</p>
</div>
</section>
<footer>
<div class="footer">
<p>© 2017 <a href="http://dobrywebdev.pl" target="_blank">Michał Grochowski - Dobrywebdev.pl</a></p>
</div>
</footer>
<script src="js/script.js"></script>
</body>
</html>
I know that it's not perfect and I will gladly accept any criticism of above code, but mostly I want to solve that localStorage issue.