Add click event on button “Remove” - So that by click on button “REMOVE” created item would be removed from localstorage as well.
Add click event on button “Edit” - So that created item could be edited in localstorage as well.
Thank you a lot for your time and effort. See my codepen
I dont know how to do it. Its not an assignment its just my pet project for myself. I started to learn js 2 month ago and its really tough for me. I was thinking that in this forum someone could help me by showing how i can make them buttons work.
You can see that each task is created as an input that has been set to disabled. I’m thinking clicking on edit would remove that disabled property letting you edit the existing task.
There is also an id on the parent list element, so that you can edit or delete the correct task from storage.
Okay, but i am more worried about js
I updated my code by the way.
Now I am able to delete element, but not from localstorage and I add random id.
Thats all what i can. Other ways i just dont understand.
yes, I understand and its true.
I just want to finish it in a way I started.
Could you please help me to delete element from localstorage using my randon id number?
Hi @dimerdelit, well I have tried to stick roughly to your code.
const addMessage = document.querySelector('.message');
const addName = document.querySelector('.name');
const addButton = document.querySelector('.add');
const todo = document.querySelector('.todo');
const remove = document.querySelector('.remove');
let todoList = [];
function uniqueId() {
return Math.random().toString(16).slice(2);
}
// a function to update the storage
// and update the displayed list
function updateTodoList (todoList) {
localStorage.setItem('todo-list', JSON.stringify(todoList));
displayMessages(todoList);
}
if (localStorage.getItem('todo-list')) {
todoList = JSON.parse(localStorage.getItem('todo-list'));
displayMessages(todoList);
}
addButton.addEventListener('click', function () {
// use or '||' instead of '+'
if (!addMessage.value || !addName.value) return;
const newTodo = {
id: uniqueId(),
name: addName.value,
message: addMessage.value,
checked: false,
important: false
};
addMessage.value = '';
addName.value = '';
todoList.push(newTodo);
updateTodoList(todoList);
});
// onClick="removeMessage('${todo.id}')"
// passes the id to removeMessage
function removeMessage (id) {
// iterate through the existing todoList
// and using filter remove the todo that has an id
// matching the todo we clicked delete on
todoList = todoList.filter(
function(todo) {
// only return the ones that don't match
return todo.id !== id;
}
)
updateTodoList(todoList);
}
function displayMessages(todoList = []) {
// Iterate through each todo with map.
// For each todo return the list item HTML
const messages = todoList.map(
function(todo) {
return `
<li id="${todo.id}">
Name:${todo.name}
Message:${todo.message}
<button class="remove" onClick="removeMessage('${todo.id}')">DELETE</button>
<button class="edit">EDIT</button>
</li>
`;
}
);
// join the array items into one big string
// using a newline as a separator.
todo.innerHTML = messages.join('\n');
}
Here is a codepen. You will obviously need to work on your css/html.
Functions that I have used, which are worth looking at.
Note: Personally I would make further changes to this, but didn’t want to veer too far off from your original code.
Edit: Just made a change to your inline onClick handler. Now passes the id to removeMessage instead. I would personally opt for addEventListener, but this is a simpler solution to passing the button element.
fieldset are quite handy. We can disable or enable all inputs and they come with an elements array that enables us to select the inputs by name e.g.
const name = myFieldSet.elements.name;
const message = myFieldSet.elements.message;
I have amended the code refactoring it into a few more shorter functions. For instance I have a function that creates the html template. Personally I quite like to have these template functions in their own module.
Anyway here is the code. It is rough around the edges and can be improved on.
// A template function to create the list item HTML
function createTodoHTML (todo) {
return `
<li id="${todo.id}">
<fieldset disabled>
<label>Name:
<input type="text" name="name" value="${todo.name}">
</label>
<label>Message:
<input type="text" name="message" value="${todo.message}">
</label>
</fieldset>
<button class="remove" onClick="removeTodo('${todo.id}')">DELETE</button>
<button class="edit" onClick="editTodo(this)">EDIT</button>
</li>
`
}
function uniqueId() {
return Math.random().toString(16).slice(2);
}
// A factory function to create a new todo object
function createTodo (name, message) {
return {
id: uniqueId(),
name: name,
message: message,
checked: false,
important: false
};
}
// a function to update the storage
// and update the displayed list
function updateTodoList (todoList) {
localStorage.setItem('todo-list', JSON.stringify(todoList));
displayTodos(todoList);
}
// as we have editTodo and removeTodo it makes
// sense to have addTodo
function addTodo (name, message) {
const newTodo = createTodo(name, message);
todoList.push(newTodo);
updateTodoList(todoList);
}
function removeTodo (id) {
todoList = todoList.filter(
function(todo) {
return todo.id !== id;
}
)
updateTodoList(todoList);
}
function editTodo (editButton) {
const listItem = editButton.parentElement;
const fieldset = listItem.querySelector('fieldset');
const editing = editButton.textContent === 'EDIT';
// fieldsets have an elements array that allow
// you to access the inputs by input name
const name = fieldset.elements.name;
const message = fieldset.elements.message;
if (editing) {
editButton.textContent = 'SAVE';
fieldset.disabled = false; // now we can edit the inputs
name.focus(); // move cursor to name
return; // exit here
}
// otherwise the button clicked is 'SAVE'
editButton.textContent = 'EDIT';
fieldset.disabled = true;
// Iterate through the todos
todoList = todoList.map(function(todo) {
// if the todo id matches the list item id then ammend
if (todo.id === listItem.id) {
todo.name = name.value;
todo.message = message.value;
}
return todo;
})
updateTodoList(todoList);
}
function displayTodos (todoList = []) {
const todos = document.querySelector('.todos');
const messages = todoList.map(function(todo) {
// return a new list item template for each todo
return createTodoHTML(todo);
});
todos.innerHTML = messages.join('\n');
}
// A generic function to reset fields
// Using the rest operator e.g ...fields
// to convert all arguments to an array
// e.g. resetFields(name, message) → [name, message]
function resetFields (...fields) {
fields.forEach(function(field) {
field.value = "";
})
}
// Moved addButton here. Saves having to scroll to the top of the code
// to find out what addButton is
const addButton = document.querySelector('.add');
addButton.addEventListener('click', function(event) {
// event.target is the button, parent is the wrapping div
const parent = event.target.parentElement;
// parent can be used as the root to search from
const message = parent.querySelector('.message');
const name = parent.querySelector('.name');
if (!name.value || !message.value) return;
addTodo(name.value, message.value);
resetFields(name, message);
});
let todoList = [];
if (localStorage.getItem('todo-list')) {
todoList = JSON.parse(localStorage.getItem('todo-list'));
displayTodos(todoList);
}
I went for fieldsets and inputs, because that seemed more straight forward. They also allowed me to use focus to focus on the name box when editing. If you want to stick with the direction you are going in I am sure you could amend my code to work with editable content instead.
Very interesting my friend I am really appreciated for your help, time and effort. I will analyse the code on weekend. fieldset is something new to me, but i will definitely use it from now. Thank you for your really useful comments in a code. Hope to meet you next time I get stuck .Big thank you again for your support and take care