JavaScript Class Constructor and DOM (Updated) - javascript

I am new to programming, and I don't quite grasp the idea of utilizing class constructor in real life. For instance, let's just say I am trying to create a DOM event handler so I can take user input and push it into CreateTodoList.todos array.
class CreateTodoList {
constructor(list) {
this.todoList = list;
this.todos = [];
}
Then let's just assume that I have built addTodo() function which takes text parameter where an user enters her/his todo.
addTodo(text) {
this.todos.push(text);
this.todoList.appendChild(CreateTodoList.addtoList(text));
}
Here, addtoList creates DOM element that takes value of the user input.
This addTodo function, then pushes the text parameter into the array I made in constructor, while also calling addtoList that makes the DOM element.
Now, let's say I click on "add" button where it takes user input value.
I will build an event handler that responds to click which will add user input to the todoList.
CreateTodoList.eventHandler('click', (e) => {
let userText.todos = document.querySelector(#userInput).value;
addTodo(userText);
})
I am trying to build an eventHandler here, so I can add user input to todoList, and have implemented this several times, but had no luck but receiving reference error.
Below is my full code.
/** #format */
const add = document.querySelector('#btn_add');
let addInput = document.querySelector('#add');
const form = document.querySelector('#form');
class CreateTodoList {
constructor(list) {
this.todoList = list;
this.todos = [];
}
addtoList(text) {
let checkboxEl = document.createElement('span');
checkboxEl.classList.add('round');
let checkboxEl2 = document.createElement('input');
checkboxEl2.id = 'checkbox';
checkboxEl2.type = 'checkbox';
let checkboxEl3 = document.createElement('label');
checkboxEl3.htmlFor = 'checkbox';
checkboxEl.appendChild(checkboxEl2);
checkboxEl.appendChild(checkboxEl3);
let todoTextEl = document.createElement('input');
todoTextEl.value = text;
todoTextEl.disabled = true;
todoTextEl.classList.add('edit_input');
todoTextEl.id = 'edit_input';
todoTextEl.type = 'text';
todoTextEl.name = 'edit_input';
let todoTextEl2 = document.createElement('label');
todoTextEl2.htmlFor = 'edit_input';
let editEl = document.createElement('i');
editEl.classList.add('far');
editEl.classList.add('fa-edit');
let deleteEl = document.createElement('i');
deleteEl.classList.add('far');
deleteEl.classList.add('fa-trash-alt');
let dateEl = document.createElement('small');
dateEl.textContent = timeago.format(new Date());
let liEl = document.createElement('li');
liEl.appendChild(checkboxEl);
liEl.appendChild(todoTextEl);
liEl.appendChild(todoTextEl2);
liEl.appendChild(editEl);
liEl.appendChild(deleteEl);
liEl.appendChild(dateEl);
let list = document.querySelector('ul');
list.appendChild(li);
return liEl;
}
removeFromList(text) {
let list = document.querySelector('ul');
let childs = Array.from(list.childNodes);
let removable = child.find((i) => i.innerText === text);
return item;
}
//todos 배열(todo 데이터에) text를 추가한다.
//todoList 에 liEL(리스트 엘레먼트) 를 append 한다.
addTodo(text) {
this.todos.push(text);
this.todoList.appendChild(CreateTodoList.addtoList(text));
}
removeTodo(text) {
let removed = this.todos.filter((el) => el !== text);
todo.todoList.removeChild(CreateTodoList.removeFromList(text));
this.todos = removed;
}
get getList() {
return this.todos;
}
}
class Handlers {}

Related

How do I updated an object's value inside an array through user input?

How do I implement/execute where once I click the edit button it will allow the user to input a value then once submitted, the text in the li will render the updated value?
JS code block is written below:
P.S. You can ignore the other functions that are irrelevant.
P.S. I know, the edittask is incomplete but I'm not exactly sure how to implement the functionality I mentioned above.
const alertMsg = document.querySelector('.alert-message');
const inputForm = document.querySelector('.input-section');
const todoInput = document.querySelector('.todo-input');
const addBtn = document.querySelector('.add-btn');
const taskActions = document.querySelector('.task-actions');
const todosList = document.querySelector('.todos-list');
const deleteAllBtn = document.querySelector('.delete-all-btn');
const savedTodos = localStorage.getItem('todos');
let todos = [];
function displayTodos(newTodoObj){
const li = document.createElement('li');
li.id = newTodoObj.id;
li.className = 'task-container'
const task = document.createElement('span');
const checkBtn = document.createElement('button')
const editBtn = document.createElement('button')
const deleteBtn = document.createElement('button')
task.innerText = newTodoObj.text;
checkBtn.innerText = 'Check'
editBtn.innerText = 'Edit';
deleteBtn.innerText = 'Del';
checkBtn.addEventListener('click', (event) => {
const task = event.target.parentElement;
console.log(task);
task.classList.toggle('completed');
})
editBtn.addEventListener('click', editTask)
deleteBtn.addEventListener('click', deleteTask)
li.appendChild(task);
li.appendChild(checkBtn);
li.appendChild(editBtn);
li.appendChild(deleteBtn);
todosList.appendChild(li);
}
function editTask(event){
const li = event.target.parentElement.children[0].innerText;
todoInput.value = li;
}
function deleteTask(event){
const li = event.target.parentElement;
li.remove();
todos = todos.filter((todo) => todo.id !== parseInt(li.id));
saveTodos();
}
function handleTodoSubmit(event){
event.preventDefault();
const newTodo = todoInput.value;
todoInput.value = '';
const newTodoObj = {
text: newTodo,
id: Date.now(),
checked: false
};
todos.push(newTodoObj);
displayTodos(newTodoObj);
saveTodos();
}
function saveTodos(){
localStorage.setItem('todos', JSON.stringify(todos));
}
inputForm.addEventListener('submit', handleTodoSubmit);
if(savedTodos !== null){
const parsedTodos = JSON.parse(savedTodos);
parsedTodos.forEach(displayTodos);
}
window.addEventListener('beforeunload', saveTodos);
This code adds an input element to the DOM when the "Edit" button is clicked, sets its value to the text of the task, and adds an event listener that listens for the "Enter" key. When the "Enter" key is pressed, the code updates the text of the task and replaces the input element with a span element containing the updated text. It also updates the todos array and saves the updated array to local storage.
function editTask(event){
const li = event.target.parentElement;
const task = li.children[0];
const input = document.createElement('input');
input.value = task.innerText;
li.replaceChild(input, task);
input.focus();
input.addEventListener('keydown', (event) => {
if (event.key === 'Enter') {
const newTask = document.createElement('span');
newTask.innerText = input.value;
li.replaceChild(newTask, input);
const todoIndex = todos.findIndex((todo) => todo.id === parseInt(li.id));
todos[todoIndex].text = newTask.innerText;
saveTodos();
}
});
}
You can use this code in your existing JavaScript file by replacing the current editTask function with this one.
I don't know if I understood your question very well, but I hope it will at least help guide you. Or maybe it is the complete solution. Best wishes!

Why won't all of my new notes inherit the button function?

I have the following JavaScript code that is triggered once DOM is loaded:
const add_note = () => {
// Creates a new note and its props
const new_note = document.createElement("div");
const new_input = document.createElement("input");
const new_form = document.createElement("form");
const new_ol = document.createElement("ol");
const new_button = document.createElement("button");
//Populates the new note with inputs and checkboxes
for (let i = 0; i < 5; i++) {
let new_li = document.createElement("li");
let new_checkbox = document.createElement("input");
new_checkbox.setAttribute("type", "checkbox");
let new_li_input = document.createElement("input");
new_li_input.classList.add("li_input");
new_ol.appendChild(new_li);
new_li.appendChild(new_checkbox);
new_li.appendChild(new_li_input);
}
//New note's settings
new_note.setAttribute("id", "note");
new_note.classList.add("note");
new_note.appendChild(new_input);
new_input.classList.add("note_input");
new_input.setAttribute("placeholder", "Note's title");
new_note.appendChild(new_form);
new_form.appendChild(new_ol);
new_ol.setAttribute("id", "ol_id");
new_note.appendChild(new_button);
new_button.classList.add("more_items");
new_button.setAttribute("id", "more_items");
//Inserts the new note and button
const note_block = document.getElementById("notes");
note_block.appendChild(new_note);
const button = document.getElementById("more_items");
button.addEventListener("click", add_more_items);
button.innerHTML = "+";
};
However, once the notes are created, only the first note button inherits its functions as seen on the following image:
Code loaded
I've tried about everything I can but couldn't figure it out. Anyway thanks in advance.
IDs are unique in html, you can't have multiple elements with the same id
Either remove these lines, make them into classes, or somehow distinguish them:
new_note.setAttribute("id", "note");
...
new_ol.setAttribute("id", "ol_id");
...
new_button.setAttribute("id", "more_items");
And just refer to the button with the variable:
const note_block = document.getElementById("notes");
note_block.appendChild(new_note);
new_button.addEventListener("click", add_more_items);
new_button.innerHTML = "+";
You could actually even move these last two lines up to the rest of your code before appending the note block.

Implement local storage for todo list

Having an issue with implementing Local Storage into my To-do list. I watched a ton of videos, understood the syntax etc. but I cannot figure out how to implement it into my code. What am trying to achieve is for the To-do app to save the tasks(make them stay at the site after reload) and store them inside the local storage.
window.addEventListener('load', () => {
const form = document.querySelector("#new-task-form");
const input = document.querySelector("#new-task-input");
const list_el = document.querySelector("#tasks");
const storeTasks = [];
localStorage.setItem('Stored Task', JSON.stringify(storeTasks));
storeTasks.append(input.value);
localStorage.getItem('Stored Task');
console.log(storeTasks);
/*localStorage.setItem('tasks', "list_el");
localStorage.getItem('list_el');*/
console.log(list_el);
form.addEventListener('submit', (e) => {
e.preventDefault();
const task = input.value;
if (!task) {
alert("Add onto the bucketlist!");
return "";
}
const task_el = document.createElement('div');
task_el.classList.add('task');
const task_content_el = document.createElement('div');
task_content_el.classList.add('content');
task_el.appendChild(task_content_el);
const task_input_el = document.createElement('input');
task_input_el.classList.add('text');
task_input_el.type = 'text';
task_input_el.value = task;
task_input_el.setAttribute('readonly', 'readonly');
task_content_el.appendChild(task_input_el);
const task_actions_el = document.createElement('div');
task_actions_el.classList.add('actions');
const task_edit_el = document.createElement('button');
task_edit_el.classList.add('edit');
task_edit_el.innerText = 'Edit';
const task_delete_el = document.createElement('button');
task_delete_el.classList.add('delete');
task_delete_el.innerText = 'Delete';
task_actions_el.appendChild(task_edit_el);
task_actions_el.appendChild(task_delete_el);
task_el.appendChild(task_actions_el);
list_el.appendChild(task_el);
input.value = '';
task_edit_el.addEventListener('click', (e) => {
if (task_edit_el.innerText.toLowerCase() == "edit") {
task_edit_el.innerText = "Save";
task_input_el.removeAttribute("readonly");
task_input_el.focus();
} else {
task_edit_el.innerText = "Edit";
task_input_el.setAttribute("readonly", "readonly");
}
});
task_delete_el.addEventListener('click', (e) => {
list_el.removeChild(task_el);
});
});
});
It appears the problem is that you save the list to the local storage before you add items to it.
And then try to change it.
LocalStorage doesn't "update" when you change the variable you saved. It updates when you tell it to update, so you need to call localStorage.setItem whenever you add new items.
And remember that localStorage saves a String, so you gonna need to JSON.parse your result from localStorage.getItem to turn it back into JS object.

how to create a list in todo app more than one time (only javascript)

i move var liElement = document.createElement('li'); out side the function addTodo() to make this function work
function removeTodo(){
liElement.remove()
};
but now i have another problem that is i can't add more than one todo (li)
const input = document.getElementById('input');
const addBtn = document.getElementById('btn');
const todoList = document.getElementById('todoList');
var ulElement = document.createElement('ul');
var liElement = document.createElement('li');
let placeholderValue = '';
// This code is for clear placeholder value
input.addEventListener('focus' , () => {
placeholderValue = input.placeholder;
input.placeholder = '';
});
input.addEventListener('blur' , ()=> {
input.placeholder = placeholderValue;
});
// this function is for add to do to a list
function addTodo(){
todoList.appendChild(ulElement)
ulElement.appendChild(liElement);
liElement.classList.add('liElement')
liElement.innerHTML = input.value;
};
addBtn.addEventListener('click' , addTodo)
// this function is for remove todo from the list
function removeTodo(){
liElement.remove()
};
liElement.addEventListener('contextmenu' , (e) => {
e.preventDefault()
removeTodo()
});
You don't use createTextNode for example :
var t = document.createTextNode(input.value);
liElement.appendChild(t);
...and you have builded a very complex structure. Make it easier for yourself.
And finally
const todoList = document.getElementById('todoList');
var ulElement = document.createElement('ul');
why use to createElements ? you don't need these. You can create them in html file.

Remove one item from an array when clicked by only js

I am new to JavaScript. I have a small code that creates list from input and then adds it to an array. I am able to remove one item from the DOM when the item is clicked, but I couldn't remove it from the array.
I tried to use array.splice(item, 1)
lists.addEventListener("click", function (e) {
e.target.closest("li").remove();
userInputArr.splice(item, 1);});
But it removes the entire array sometime, and sometime removes the last item. when I console log the code, it looks like I clicked 3 or 4 times on the list even though I just clicked once. I have no idea what's wrong. this is the entire code:
const lists = document.querySelector(".lists");
const userInput = document.querySelector(".add-note");
const addBtn = document.querySelector(".add-btn");
const item = document.querySelectorAll(".list");
userInputArr = [];
function addNote() {
if (userInput.value < 1) {
return;
}
lists.insertAdjacentHTML(
"afterbegin",
`<li class='list'>${userInput.value}</li>`
);
userInputArr.push(lists);
lists.addEventListener("click", function (e) {
e.target.closest("li").remove();
userInputArr.splice(item, 1);
});
userInput.value = "";
}
addBtn.addEventListener("click", function () {
addNote();
});
Code is totally meaningless
1)
userInputArr.push(lists)
why you push the same element all the time? As lists refers to the first and the only element with class 'lists'?
2)
userInputArr.splice(item, 1)
please watch carefully what splice does? The first argument is number, but you pass a collection of elements with class 'list'. But i camn not even suggest which element should be removed as it contains the same element as i mentioned in first point
3) You do not need this array at all
So right approach is something like this
const lists = document.querySelector(".lists");
// just once create listener, no need to do it each time
lists.addEventListener("click", function (e) {
// if you want to remove clicked item then
if (e.target.tagName === 'LI') e.target.remove();
// but if you want to remove the first one then uncomment line
// if (this.children[0]) this.children[0].remove()
});
const userInput = document.querySelector(".add-note");
const addBtn = document.querySelector(".add-btn");
///////////////////////////////////////////////////
// item is meaninglee here, so delete this line
// const item = document.querySelectorAll(".list");
//////////////////////
// array is useless too, delete this line
// userInputArr = [];
function addNote() {
// check if it is number
if (isNaN(userInput.value) || Number(userInput.value < 1)) {
return;
}
lists.insertAdjacentHTML(
"afterbegin",
`<li class='list'>${userInput.value}</li>`
);
userInput.value = "";
}
addBtn.addEventListener("click", function () {
addNote();
});
const items = (() => {
const _items = {};
let key = 0;
return {
put(value) {
_items[key++] = value;
console.log("Added", this.all());
return key - 1;
},
remove(key) {
delete _items[key++];
console.log("Removed", this.all());
},
all(asArray = true) {
return asArray ? Object.values(_items) : { ..._items
};
}
}
})();
const inputEl = document.querySelector(".input");
const itemsEl = document.querySelector(".items");
const addBtn = document.querySelector(".btn-add");
addBtn.addEventListener("click", () => {
const value = inputEl.value.trim();
if (!value.length) return;
const key = items.put(value);
const li = document.createElement("li");
li.textContent = value;
li.dataset.key = key;
itemsEl.append(li);
inputEl.value = "";
});
itemsEl.addEventListener("click", (e) => {
const li = e.target.closest("li");
items.remove(li.dataset.key);
li.remove();
});
<input type="text" class="input">
<button class="btn-add">Add</button>
<ul class="items"></ul>
Run code & View in full screen.
use shift() userInputArr.shift()
you are also getting double clicks because your addNote() function contains an event listener lists.addEventListener and it's executed by another event listner addBtn.addEventListener you should probably move
lists.addEventListener out of the addNote function

Categories

Resources