I am doing some practice javascript exercise. My project look like 'trello' but much soft and simple.
When i writing some notes to input, javscript adding note dynamically but if i refresh the page/chrome, all things gone or lost.
So i wanna apply localstorage on my project. How can i do it.
My Note project: https://codepen.io/daniel_134/pen/NWwYKyK[My Note project]1
var input = document.querySelector('#text-input');
document.querySelector("#ad-note-btn").addEventListener("click", () => {
if (input.value.length > 1) {
// GET-INPUT-VALUE
var getvalue = input.value;
// CREATE-NEW-NOTE
const newLi = document.createElement("textarea");
newLi.value = getvalue;
newLi.className = "note-li";
// ADD-NEW-NOTE
var ul = document.querySelector('#list-items');
ul.appendChild(newLi);
// EMPTY-INPUT-WHEN-CREATING-NEW-NOTES
input.value = " ";
// DELETE-NOTES
const dleLi = document.createElement("button");
dleLi.textContent = "delete";
dleLi.className = "list-btn";
ul.appendChild(dleLi);
dleLi.addEventListener("click", () => {
newLi.remove();
dleLi.remove();
edLi.remove();
saveLi.remove();
})
// EDIT-NOTES
const edit = () => {
if( newLi.value.length > 0 ) {
newLi.disabled = true;
} else {
newLi.disabled = false;
}
}
edit()
const edLi = document.createElement("button");
edLi.textContent = "Edit";
ul.appendChild(edLi);
edLi.className = "list-btn";
edLi.addEventListener("click", () => {
if ( newLi.disabled = true ) {
newLi.disabled = false;
}else {
newLi.disabled = true;
}
})
const saveLi = document.createElement("button");
saveLi.textContent = "save";
ul.appendChild(saveLi);
saveLi.className = "list-btn";
saveLi.addEventListener("click", () => {
edit();
})
} else {
ul.appendChild();
}
})
document.querySelector("#clear-btn").addEventListener("click", () => {
input.value = " ";
})
2
it'll look like that , for example :
when you load your page .
load todoList var todoList = JSON.parse(localStorage.getItem('todo-list'))
and display it
when you add new element to your to-do list
var todoList = JSON.parse(localStorage.getItem('todo-list'));
var new_todo = [{
title:'for example ...',
complete:false
}];
localStorage.setItem('todo-list',JSON.stringify(new_todo));
}else{
todoList.push({
title:'for example ...',
complete:false
});
localStorage.setItem('todo-list',JSON.stringify(todoList));
}
Related
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.
Brief synopsis of what i am trying to do:
I have a list with the following fields: document type, title of the entry, and an attachments field.
I need to get the entries along with the url(s) to the attachment(s) for the list item. I have it mostly figured out, but i can't seen to get the process to wait until i have all the information before sending it to the browser page. I know how to get the things separately, but do not know how to - or if it's even possible - to get the list item and attachment info at the same time - rather than doing two separate async queries.
I would like to get the list items, group them by document type and display separate groupings on the page that open an attachment modal when you click the item's displayed title. When i try to do this, it always paints the items before the attachments are actually added to the JSON object data.
here is the code i have
var fileList = [];
var finished = false;
function loadBootstrap() {
//check for the required boostrap stuff
var bootJs = document.querySelector('head').querySelector('#bootstrap-js');
if (!bootJs) {
bootJs = document.createElement('script');
bootJs.setAttribute("src", "https://cdn.jsdelivr.net/npm/bootstrap#4.6.1/dist/js/bootstrap.bundle.min.js");
bootJs.id = "bootstrap-js";
document.querySelector('head').append(bootJs);
}
var popper = document.querySelector('head').querySelector('#popper');
if (!popper) {
popper = document.createElement('script');
popper.setAttribute("src", "https://cdn.jsdelivr.net/npm/popper.js#1.16.1/dist/umd/popper.min.js");
popper.id = "popper";
document.querySelector('head').append(popper);
}
}
function getList() {
try {
if (typeof $().jquery === 'unefined') {
let jqueryJs = document.createElement('script');
jqueryJs.setAttribute("src", "/netcom/sites/516SB/SiteAssets/JScripts/jquery-3.3.1.min.js");
jqueryJs.id = "jquery-js";
document.querySelector('head').append(jqueryJs);
let jqueryWaiter = setInterval(() => {
if (typeof $().jquery !== 'unefined') {
clearInterval(jqueryWaiter);
jqueryWaiter = null;
loadBootstrap();
}
});
} else {
loadBootstrap()
}
} catch {
let jqueryJs = document.createElement('script');
jqueryJs.setAttribute("src", "/netcom/sites/516SB/SiteAssets/JScripts/jquery-3.3.1.min.js");
jqueryJs.id = "jquery-js";
document.querySelector('head').append(jqueryJs);
let jqueryWaiter = setInterval(() => {
if (typeof $ !== "undefined" && typeof $().jquery !== 'unefined') {
clearInterval(jqueryWaiter);
jqueryWaiter = null;
loadBootstrap();
}
});
}
getListItems('Staff Docs List',
function (listItems) {
for (var i = 0; i < listItems.length; i++) {
GetAttachments(listItems[i],
function (sendera, args) {
console.log(args.get_message());
});
fileList.push(listItems[i]);
}
let finishedWaiter = setInterval(() => {
let totalFilesWithAttachments = fileList.map(x => x.hasAttachments).length;
let totalAttachmentsFinished = fileList.map(x => x.attachements!==undefined).length;
if (totalAttachmentsFinished == totalFilesWithAttachments) {
clearInterval(finishedWaiter);
finished = true;
buildIt();
}
});
},
function (sendera, args) {
console.log(args.get_message());
});
}
class AttachmentWindow {
constructor(attachementList, itemName) {
this.html = this.build();
}
build() {
let html = document.createElement('div');
html.className = "modal fade";
html.id = "myModal";
html.innerHTML = `<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header"> Documents for <span class="item-name"></span>
<button class="close btn bnt-danger" aria-label="close modal" data-dismiss="modal">✕</button>
</div>
<div class="modal-body">
</div>
</div>`
return html;
}
}
class StaffDocs {
constructor(item) {
this.title = item.title;
this.attachments = item.attachments;
return this.build();
}
build() {
let html = document.createElement('div');
html.className = "document-item";
html.innerText = this.title;
html.title = "click to see attachments";
html.dataset.toggle = "modal";
html.dataset.target = "#myModal";
html.addEventListener('click', () => {
let modal = document.querySelector('.modal');
let title = modal.querySelector('.item-name');
title.innerText = this.title;
let content = modal.querySelector('.modal-body');
content.innerHTML = '';
this.attachements.forEach(item => {
let attachmentDiv = document.createElement('div');
attachmentDiv.innerHTML = `<div>${item.name}</div>`;
content.append(attachmentDiv);
});
});
return html;
}
}
class DocCategory {
constructor(typeName, files) {
this.typeName = typeName;
this.items = files;
this.css();
return this.build();
}
build() {
let div = document.createElement('div');
div.className = this.typeName.replace(' ', '');
div.className += " flex flex-box";
div.innerHTML = `<h2>${this.typeName}</h2><hr />`;
let fileContents = document.createElement('div');
div.append(fileContents);
fileContents.className = "fileList";
this.items.forEach(item => {
let doc = new StaffDocs(item);
fileContents.append(doc);
});
return div;
}
css() {
var style = document.querySelector('head').querySelector('#staffDocsCss');
if (!style) {
style = document.createElement('style');
document.querySelector('head').append(style)
style.id = "staffDocsCss";
style.type = "text/css";
let cssText = `.${this.typeName.replace(' ', '')}{display:flex; width:100%;flex-overflow:wrap;margin-bottom:50px;}
.${this.typeName.replace(' ', '')} .document-item{flex - basis:row;width:100%}`;
style.append(document.createTextNode(cssText));
}
}
}
function buildIt() {
var waiter = setInterval(() => {
if (finished) {
clearInterval(waiter);
let modal = new AttachmentWindow().html;
document.querySelector('body').append(modal);
let docTypes = fileList.map(x => x.documentCategory);
let target = document.querySelector('.staff-doc-area');
target.innerHTML = '';
docTypes.forEach(doc => {
let files = fileList.filter(x => x.documentCategory == doc);
let category = new DocCategory(doc, files);
target.append(category);
});
}
}, 10)
}
function getListItems(listTitle, success, error) {
let ctx = SP.ClientContext.get_current();
let list = ctx.get_web().get_lists().getByTitle(listTitle);
let qry = new SP.CamlQuery();
let listItems = list.getItems(qry);
ctx.load(listItems);
ctx.executeQueryAsync(
function () {
let listItemEnumerator = listItems.getEnumerator();
let attachmentsList = [];
while (listItemEnumerator.moveNext()) {
let item = listItemEnumerator.get_current();
Item = item;
let title = item.get_item('Title');
let documentCategory = item.get_item('Document_x0020_Type');
let hasAttachments = item.get_fieldValues()['Attachments'];
attachmentsList.push({
title: title,
documentCategory: documentCategory,
hasAttachments: hasAttachments,
fileDirRef: item.get_fieldValues()['FileDirRef'],
Id: item.get_fieldValues()['ID'],
shown: item.get_fieldValues()["Shown_x0020_on_x0020_List"]
});
}
success(attachmentsList);
},
error);
}
function GetAttachments(listItem, error) {
if (listItem.hasAttachments) {
let ctx = SP.ClientContext.get_current();
let attachmentFolderUrl = String.format('{0}/Attachments/{1}', listItem.fileDirRef, listItem.Id);
let folder = ctx.get_web().getFolderByServerRelativeUrl(attachmentFolderUrl);
let files = folder.get_files();
ctx.load(files);
ctx.executeQueryAsync(
function () {
let attachments = [];
for (let i = 0; file = files.get_item(i); i++) {
attachments.push({ url: file.get_serverRelativeUrl(), name: file.get_name() });
}
listItem["attachments"] = attachments;
},
error);
}
}
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', getList);
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');
I am making a list where you can edit or delete items. I am listening for 2 events on the same table. One for edit and one for delete, I am listening on the table and not the actual buttons as they are created dinamycally. Edit and Delete both have the same id, the id of the product, which I am using later for the http requests.
,
Now when I press edit the console.logs from the delete functions fire up,but nothing happens, if I am trying to save the item the http request doesnt work, it will not take the id (but it logs it to the console)
If I press the delete button once nothing happnes, if I press it a second time the page refreshes and the item is deleted.
Is there a way to listen for those events separately or for them to not interfere with one another? All I want is if I press the edit button the respective item's values to go to the input field and when I press Add Item update the product in the JSON file as well, and on delete press, to delete the item from the JSON file and remove from the html document.
Update: Managed to resolve edit function
Here is my code:
import { http } from "./http.js";
import { ui } from "./ui.js";
const productsURL = "https://61363d1a8700c50017ef54c1.mockapi.io/product";
// const addProductBtn = document.querySelector('.new-product-btn');
const adminContainer = document.querySelector('.admin-container');
const addItem = document.querySelector('.admin-add-item-btn');
const imgInput = document.getElementById('image');
const nameInput = document.getElementById('name');
const priceInput = document.getElementById('price');
const stockInput = document.getElementById('stock');
const categoryInput = document.getElementById('category');
const typeInput = document.getElementById('type');
const descriptionInput = document.getElementById('description');
const validSvg = document.querySelectorAll('.valid_input_svg');
// const adminForm = document.getElementById('admin-form');
const adminTable = document.getElementById('admin-tbody');
const editBtn = document.querySelectorAll('.edit-btn');
const adminBtn = document.querySelectorAll('.admin-delete-btn');
const cancel = document.getElementById('cancel');
let productToEdit;
let edit = false;
let id;
document.addEventListener('DOMContentLoaded', listAdminProducts);
// adminForm.addEventListener('submit', validateInput);
addItem.addEventListener('click', addOrEditProducts);
// adminTable.addEventListener('click', editOrDeleteItem);
adminTable.addEventListener('click', deleteProduct);
adminTable.addEventListener('click', editProduct);
cancel.addEventListener('click', cancelEdit);
function listAdminProducts() {
http.get(productsURL).then(products => {
ui.showAllAdminProducts(products);
});
};
function addOrEditProducts() {
if (edit === true && validateInput() === true) {
productToEdit = {
image: imgInput.value,
name: nameInput.value,
price: priceInput.value,
stock: stockInput.value,
category: categoryInput.value,
type: typeInput.value,
description: descriptionInput.value,
};
http
.put(`${productsURL}/${id}`, productToEdit)
.then(() => listAdminProducts());
console.log(`${productsURL}/${id}`)
ui.clearFields();
id = '';
edit = false;
return;
} else if (edit === false && validateInput() === true) {
const product = {
image: imgInput.value,
name: nameInput.value,
price: priceInput.value,
stock: stockInput.value,
category: categoryInput.value,
type: typeInput.value,
description: descriptionInput.value
};
http.post(productsURL, product).then(() => listAdminProducts());
ui.clearFields();
};
};
function editProduct(e) {
console.log('works');
if (e.target.classList.contains('edit-btn')) {
edit = true;
id = e.target.getAttribute('id');
console.log(id);
console.log(e.target)
http.get(`${productsURL}/${id}`).then((data) => {
imgInput.value = data.image;
nameInput.value = data.name;
priceInput.value = data.price;
stockInput.value = data.stock;
categoryInput.value = data.category;
typeInput.value = data.type;
descriptionInput.value = data.description;
});
console.log(`${productsURL}/${id}`)
};
// id = '';
}
function deleteProduct(e) {
console.log(e.target);
if (e.target.className === 'admin-delete-btn') {
console.log(e.target);
id = e.target.getAttribute('id');
console.log(id);
http
.delete(`${productsURL}/${id}`)
.then(() => listAdminProducts())
.catch("Error on delete");
id = '';
}
ui.showSuccessMessage('Product deleted', adminContainer);
}
function cancelEdit() {
ui.clearFields;
imgInput.className = '';
nameInput.className = '';
priceInput.className = '';
stockInput.className = '';
categoryInput.className = '';
edit = false;
}
function validateInput() {
let valid = true;
if (imgInput.value == '') {
if (imgInput.classList.contains('input-invalid')) {
imgInput.classList.remove('input-invalid');
};
ui.showAdminMessage('Must contain a link to an image', 0);
imgInput.classList.add('input-invalid');
valid = false;
} else {
imgInput.classList.add('input-valid');
validSvg[0].style.display = "block";
removeClass(imgInput, 0);
};
if (nameInput.value === '') {
if (nameInput.classList.contains('input-invalid')) {
nameInput.classList.remove('input-invalid');
};
ui.showAdminMessage('Name is requierd', 1);
nameInput.classList.add('input-invalid');
valid = false;
} else {
// stockInput.classList.remove('input-invalid');
nameInput.classList.add('input-valid');
validSvg[1].style.display = "block";
removeClass(nameInput, 1);
};
if (priceInput.value == "" || isNaN(priceInput.value) || priceInput.value < 0) {
if (priceInput.classList.contains('input-invalid')) {
priceInput.classList.remove('input-invalid');
};
ui.showAdminMessage('Price must be a number greater then 0', 2);
priceInput.classList.add('input-invalid');
valid = false;
} else {
// stockInput.classList.remove('input-invalid');
priceInput.classList.add('input-valid');
validSvg[2].style.display = "block";
removeClass(priceInput, 2);
};
if (stockInput.value == "" || isNaN(stockInput.value) || stockInput.value < 0) {
if (stockInput.classList.contains('input-invalid')) {
stockInput.classList.remove('input-invalid');
};
ui.showAdminMessage('Stock must be a number greater then 0', 3);
stockInput.classList.add('input-invalid');
valid = false;
} else {
// stockInput.classList.remove('input-invalid');
stockInput.classList.add('input-valid');
validSvg[3].style.display = "block";
removeClass(stockInput, 3);
};
if (categoryInput.value === 'barware' || categoryInput.value === 'spirits') {
// categoryInput.classList.remove('input-invalid');
categoryInput.classList.add('input-valid');
validSvg[4].style.display = "block";
removeClass(categoryInput, 4);
} else {
ui.showAdminMessage('Category must be barware or spirits', 4);
categoryInput.classList.add('input-invalid');
valid = false;
};
return valid;
};
function removeClass(element, index) {
// console.log(element, index);
setTimeout(() => {
element.className = '';
validSvg[index].style.display = "none";
}, 3000)
}
Finally managed to resolve it, I had to put e.preventDefault() in both functions, so the page will not reload first
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 :)