I am pretty much new to Javascript and working on this simple ToDo app that uses local storage to persist data. However, the Delete function can only delete from local storage when refreshed the page. What could be causing this bug? I have attached my code below
I tried commenting on the e.preventDefault() on the form but the page kept on reloading when a task is submitted.
// Selectors
const ul = document.querySelector('.todo-list');
const todoContainer = document.querySelector('.todo-container');
const clearButton = document.createElement('button');
clearButton.classList.add('clear-button');
clearButton.textContent = 'Clear all Completed';
const form = document.querySelector('.form');
const taskInput = document.querySelector('.todo-input');
let todoTasks = JSON.parse(localStorage.getItem('todo')) || [];
let id = todoTasks.length + 1;
const createElement = ({ description, completed = true, index }) => {
const todoItem = document.createElement('li');
todoItem.classList.add('todo-list-item');
todoItem.setAttribute('id', index);
todoItem.innerHTML = `
<input type="checkbox" class="check" value="${completed}">
<button class="hidden" name="${index}"></button>
<span class="todo-item">${description}</span>
<button name='eclips'><i class="fas fa-ellipsis-v"></i></button>
<button name='delete'><i class="fas fa-trash"></i></button>
`;
ul.appendChild(todoItem);
todoContainer.appendChild(ul);
todoContainer.appendChild(clearButton);
};
// get each todo task
todoTasks.forEach(createElement);
// Function that add todo
const addTask = (description, completed, ind) => {
const input = taskInput.value;
todoTasks.push({
description: input,
completed: false,
index: ind,
});
localStorage.setItem('todo', JSON.stringify(todoTasks));
return { description, completed, ind };
};
const checkTodo = (e) => {
const lineText = e.target.nextElementSibling.nextElementSibling.nextElementSibling;
if (lineText.style.textDecoration === 'line-through') {
lineText.style.textDecoration = 'none';
} else {
lineText.style.textDecoration = 'line-through';
lineText.classList.toggle('completed');
}
};
// Function that delete todo
const handleDeleteAndCheck = (e) => {
const item = e.target;
if (e.target.classList[1] === 'fa-trash') {
const todo = item.parentElement.parentElement;
const targetId = item.parentElement.parentElement.id;
todoTasks = todoTasks.filter((task) => task.index !== +targetId);
localStorage.setItem('todo', JSON.stringify(todoTasks));
todo.remove();
}
if (e.target.classList === 'check') {
checkTodo();
}
};
// Function that Edit todo
const editTask = (e) => {
const item = e.target;
if (item.classList[0] === 'todo-item') {
item.contentEditable = true;
item.style.display = 'block';
}
};
const check = document.querySelectorAll('.fa-check-square');
const index = document.querySelectorAll('#index');
form.addEventListener('submit', (e) => {
e.preventDefault();
const input = taskInput.value;
const checkValue = check.value;
// const indexValue = index.value;
const newTask = addTask(input, checkValue, id);
createElement(newTask);
// location.reload();
taskInput.value = '';
id += 1;
});
ul.addEventListener('click', handleDeleteAndCheck);
ul.addEventListener('click', editTask);
Here please change the statement with this in your handleDeleteAndCheck() method. It will remove the local storage at that time.
localStorage.removeItem('todo');
Related
I was working on the todo list project, but while transferring the values written to the local storage to the UI, I encountered this error. I tried all the suggestions, but I could not do anything. What should I do?
Here is my code:
const form = document.querySelector("#todo-form");
const todoInput = document.querySelector("#todo");
const todoList = document.querySelector(".list-group");
const firstCard = document.querySelectorAll(".card-body")[0];
const secondCard = document.querySelectorAll(".card-body")[1];
const filter = document.querySelector("#filter");
const clearButton = document.querySelector("#clear-todos");
eventListeners();
function eventListeners() {
form.addEventListener("submit", addTodo);
document.addEventListener("DOMContentLoaded", loadAllTodosToUI);
}
function loadAllTodosToUI() {
let todos = getTodosFromStorage();
todos.forEach(function (todo) {
addTodoToUI(todo)
});
}
function addTodo(e) {
const newTodo = todoInput.value.trim();
if (newTodo === "") {
showAlert("danger", "bir todo gir");
} else {
addTodoToUI(newTodo);
addTodoToStorage(newTodo);
showAlert("success", "başarıyla eklendi");
}
e.preventDefault();
}
function getTodosFromStorage() {
let todos;
if (localStorage.getItem("todos") === null) {
todos = [];
} else {
todos = JSON.parse(localStorage.getItem(todos));
}
return todos;
}
function addTodoToStorage(newTodo) {
let todos = getTodosFromStorage();
todos.push(newTodo);
localStorage.setItem("todos", JSON.stringify(todos));
}
function showAlert(type, message) {
const alert = document.createElement("div");
alert.className = `alert alert-${type}`;
alert.textContent = message;
firstCard.appendChild(alert);
setTimeout(() => {
alert.remove();
}, 1000);
}
function addTodoToUI(newTodo) {
const listItem = document.createElement("li");
const link = document.createElement("a");
link.href = "#";
link.className = "delete-item";
link.innerHTML = "<i class = 'fa fa-remove'></i>";
listItem.className = "list-group-item d-flex justify-content-between";
listItem.appendChild(document.createTextNode(newTodo));
listItem.appendChild(link);
todoList.appendChild(listItem);
todoInput.value = "";
}
The console says that there is an error directly related to forEach, but the value I entered in the local storage is not null, but I get this error
I'm new to javascript and I am trying to use local storage to save user input. With the code as it is right now, I get the user input saved to local storage, but the list does not save when refreshing the page. Also, the user input appends to the to do list multiple times. Thanks for taking a look.
window.addEventListener('load', () => {
const form = document.querySelector('#new-task-form');
const input = document.querySelector('#new-task-input');
const listElement = document.querySelector('#tasks');
todos = JSON.parse(localStorage.getItem('todos')) || [];
console.log(todos)
form.addEventListener('submit', (e) => {
e.preventDefault();
const task = input.value;
if(!task) {
alert('You definitely have something to do...')
return
}
const todo = {
content: task,
id: Math.floor(Math.random() * 100000)
}
todos.push(todo);
localStorage.setItem('todos', JSON.stringify(todos));
todos.forEach(todo => {
const taskElement = document.createElement('div');
taskElement.classList.add('task');
const taskContentElement = document.createElement('div');
taskContentElement.classList.add("content");
taskElement.appendChild(taskContentElement);
const taskInputElement = document.createElement("input")
taskInputElement.classList.add("text");
taskInputElement.type = "text";
taskInputElement.value = task;
taskInputElement.setAttribute('readonly', 'readonly');
taskContentElement.appendChild(taskInputElement);
const taskActionsElement = document.createElement('div');
taskActionsElement.classList.add("actions");
const taskEditElement = document.createElement('button');
taskEditElement.classList.add('edit');
taskEditElement.innerHTML = "Edit";
const taskDeleteElement = document.createElement('button');
taskDeleteElement.classList.add('delete');
taskDeleteElement.innerHTML = "Delete";
taskActionsElement.appendChild(taskEditElement);
taskActionsElement.appendChild(taskDeleteElement);
taskElement.appendChild(taskActionsElement);
listElement.appendChild(taskElement);
input.value = '';
taskEditElement.addEventListener('click', () => {
if (taskEditElement.innerText.toLowerCase() == 'edit') {
taskInputElement.removeAttribute('readonly');
taskInputElement.focus();
taskEditElement.innerText = "Save";
localStorage.setItem("todos", JSON.stringify(todos));
} else {
taskInputElement.setAttribute('readonly', 'readonly');
taskEditElement.innerText = 'Edit';
}
});
taskDeleteElement.addEventListener('click', () => {
todos = todos.filter(t => t != todo);
localStorage.setItem('todos', JSON.stringify(todos));
listElement.removeChild(taskElement);
});
});
});
});
The user input comes up multiple times when added to the list, depending on when added to the array. I was hoping for it to come up one time, and for it to be a normal list.
i have an array named todoList, all of my data is in it.
i saved them to localstorage like this:
https://codepen.io/arashkazerouni/pen/YzLxdoQ
const saveToLocal = (array) => {
window.localStorage.setItem("todo", JSON.stringify(array));
};
todoList = JSON.parse(window.localStorage.getItem("todo"));
i used this saveToLocal function after any change in todoList, and it works.
the only problem is when i refresh the page, all items gone.
but if i add new todo, all of them will shown again
and there is page script :
const input = document.querySelector("input");
const button = document.querySelector("button");
const todos = document.querySelector(".todos");
const alertRed = document.querySelector(".alert-red");
let todoList = [];
const saveToLocal = (array) => {
window.localStorage.setItem("todo", JSON.stringify(array));
};
todoList = JSON.parse(window.localStorage.getItem("todo"));
const addToDOM = () => {
// todos.innerHTML = "";
for (let i = 0; i < todoList.length; i++) {
const html = `
<div class="todo" id=${i}>
<p class="todo-text" >${todoList[i]}</p>
<i class="fa-solid fa-check" ></i>
<i class="fa-solid fa-trash"></i>
</div>
`;
todos.insertAdjacentHTML("beforeend", html);
}
};
// Add items to list
button.onclick = (e) => {
e.preventDefault();
// todos.innerHTML = "";
if (!todoList.includes(input.value) && input.value !== "") {
todoList.push(input.value);
saveToLocal(todoList);
}
// console.log(todoList);
addToDOM();
input.value = "";
};
// Handle Enter Press
document.onkeypress = (e) => {
if (e.key === "Enter") {
button.click();
}
};
todos.onclick = (e) => {
e.preventDefault();
const isCheck = e.target.classList.contains("fa-check");
const isTrash = e.target.classList.contains("fa-trash");
if (isCheck) e.target.previousElementSibling.classList.toggle("checked");
if (isTrash) {
const element = e.target.parentElement;
const elementID = parseInt(element.id);
element.classList.add("removed");
todoList = todoList.filter((element) => element !== todoList[elementID]);
saveToLocal(todoList);
setTimeout(() => {
addToDOM();
}, 300);
}
};
I am trying to remove an item of a ToDo app both from the UI and localStorage when its delete button is clicked. I can remove the item from the UI when e.target.calssName === 'delete'. However, I can't access the index of the array in localStorage and delete the same item from there as well. Here is the code I am working on. Any help would be highly appreciated.
const addTask = document.querySelector('#addItem');
const inputForm = document.querySelector('#inputForm');
const saveButton = document.querySelector('#saveButton');
const output = document.querySelector('#output');
// Add task button
const addItem = () => {
inputForm.style.display = 'block';
taskInput.focus();
};
// Add and update item to localstorage
const checkStorage = () => {
const input = document.querySelector('#taskInput');
if(input.value) {
const task = {
name: input.value
};
if(localStorage.getItem('tasks') === null) {
const tasks = [];
tasks.push(task)
localStorage.setItem('tasks', JSON.stringify(tasks));
} else {
const tasks = JSON.parse(localStorage.getItem('tasks'));
tasks.push(task);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
} else {
return false;
};
};
// Display item on UI
const displayItem = () => {
const tasks = JSON.parse(localStorage.getItem('tasks'));
if(tasks !== null) {
const html = tasks.map((task, index) => {
return `
<ul class="item" id="${index}">
<li>${task.name}</li>
<button class="edit" id="${index}">Edit</button>
<button class="delete" id="${index}">Delete</button>
</ul>
`
}).join('');
output.innerHTML = html;
} else {
checkStorage();
};
};
// Save the task and display the item
const saveTask = (e) => {
e.preventDefault();
checkStorage();
displayItem();
inputForm.reset();
inputForm.style.display = 'none'
};
// Delete item from UI and localStorage
const deleteItem = (e) => {
const tasks = JSON.parse(localStorage.getItem('tasks'));
// Not sure how to loop throuh the tasks array and delete the item which is deleted from the UI
}
document.addEventListener('click', deleteItem);
document.addEventListener('onload', displayItem())
saveButton.addEventListener('click', saveTask);
addTask.addEventListener('click', addItem);
You can use Array#splice to delete an element from an array.
const deleteItem = (e) => {
if(e.target.classList.contains("delete")){
const tasks = JSON.parse(localStorage.getItem('tasks'));
tasks.splice(+(e.target.getAttribute("id")), 1);
localStorage.setItem('tasks', JSON.stringify(tasks));
}
}
many different ways to do this.best way is to user filter. More about filter
var tasks = JSON.parse(localStorage.getItem('tasks'));
tasks = tasks.filter(task=> "your condition");
localStorage.setItem('tasks', JSON.stringify(tasks));
Note: if you have the the id of the task it should go like this.
tasks = tasks.filter(task=> task.id != id );
So I'm a newb at web dev, and trying to get my head around JavaScript by writing a.. yeah, you guessed it, a to do list.
I've been trying to set the items to the local storage, and then retrieve it, it sorta works, however when the list items are retrieved, the buttons do not seem to function, and I can't for the life of me figure out why... Any thoughts?
Here's the code:
document.addEventListener('DOMContentLoaded', () => {
const submitButton = document.querySelector('.submit');
submitButton.type = 'submit';
const inputField = document.querySelector('.createItem');
const toDoUl = document.querySelector('.toDoUl');
const completedUl = document.querySelector('.completedUl');
const form = document.querySelector('#header');
const tdContainer = document.getElementById('tdContainer');
const toDoItems = document.getElementById('toDoItems');
(function loadStorage() {
if (localStorage.getItem('todo')) {
tdContainer.innerHTML = localStorage.getItem('todo');
}
})();
function noChildren() {
if (toDoUl.hasChildNodes()) {
tdContainer.classList.remove('tdContainer');
} else {
tdContainer.className = 'tdContainer';
}
}
function createLi() {
const wrapper = document.getElementById('wrapper');
const doneButton = document.createElement('input');
const checkedLabel = document.createElement('label');
doneButton.type = 'checkbox';
checkedLabel.className = 'done';
checkedLabel.appendChild(doneButton);
const listItem = document.createElement('li');
const p = document.createElement('p');
const editButton = document.createElement('button');
const removeButton = document.createElement('button');
toDoUl.appendChild(listItem);
p.textContent = inputField.value;
inputField.value = '';
editButton.className = 'edit';
removeButton.className = 'remove';
listItem.appendChild(checkedLabel);
listItem.appendChild(p);
listItem.appendChild(editButton);
listItem.appendChild(removeButton);
doneButton.style.display = 'none';
editButton.addEventListener('click', () => {
listItem.contentEditable = 'true';
});
listItem.addEventListener('blur', () => {
listItem.contentEditable = 'false';
});
removeButton.addEventListener('click', e => {
const ul = e.target.parentNode.parentNode;
/*const li = e.target.parentNode.parentNode;*/
ul.removeChild(e.target.parentNode);
noChildren();
});
doneButton.addEventListener('click', e => {
if (e.target.parentNode.parentNode.parentNode.className === 'toDoUl') {
completedUl.appendChild(e.target.parentNode.parentNode);
e.target.parentNode.parentNode.className = 'removeTransition';
noChildren();
localStorage.setItem('todo', tdContainer.innerHTML);
} else {
toDoUl.appendChild(e.target.parentNode.parentNode);
e.target.parentNode.parentNode.className = 'addTransition';
noChildren();
}
});
}
form.addEventListener('submit', e => {
e.preventDefault();
noChildren();
createLi();
localStorage.setItem('todo', tdContainer.innerHTML);
});
});
You can see the working version here: http://kozyrev.site/todo/
i'm glad you're writing arrow functions and cool stuff :D
but it seems that you are setting event listeners within createLi function, that is dispatched on form's submit event.
But, when you loads localStorage, is setting HTML content like this:
tdContainer.innerHTML = localStorage.getItem('todo');
event listener is not attached to them, because all of these elements that you created from localStorage, is not create by createLi function :(
but you might write something like this:
// loads from localStorage
(function loadStorage() {
if (localStorage.getItem('todo')) {
tdContainer.innerHTML = localStorage.getItem('todo');
}
})();
// set listeners below
var liSelector = '.toDoUl > li'
var liElements = document.querySelectorAll(liSelector)
Array.prototype.forEach.call(liElements, (liElement) => {
var editButton = liElement.querySelector('.edit')
console.log(editButton)
// you can set listeners here
editButton.addEventListener('click', (e) => {
e.preventDefault()
console.log('yey, event has dispatched, do your magic :)')
})
})
UPDATE: example using named function to reuse them:
function createLi() {
....
const listItem = document.createElement('li');
....
editButton.addEventListener('click', () => {
listItem.contentEditable = 'true';
});
could be written like this
// this function at top of script
const setEditable = (listItem) => {
listItem.contentEditable = 'true';
}
// you can use setEditable within createLi
function createLi() {
....
const listItem = document.createElement('li');
....
editButton.addEventListener('click', () => {
setEditable(listItem)
});
also, after HTML was written from localStorage like this
// loads from localStorage
(function loadStorage() {
if (localStorage.getItem('todo')) {
tdContainer.innerHTML = localStorage.getItem('todo');
}
})();
// set listeners below
var liSelector = '.toDoUl > li'
var liElements = document.querySelectorAll(liSelector)
Array.prototype.forEach.call(liElements, (listItem) => {
var editButton = listItem.querySelector('.edit')
// you can set listeners here
editButton.addEventListener('click', (e) => {
setEditable(listItem)
})
})
I didn't tested, but i hope it works, and it's shows you that named function could be reused for setting listeners :)