How to put the edited contents on to do list - javascript

I'm a beginner web dev learner and I'm trying to create a to-do list app by vanilla JS.
I created some main functions but now I'm stucking in 2 points.
1st.
I created an "edit" button. this button adds input textbox element into li element that surrounds each to-do task by using a map method.However, I can't come up with a proper way to replace an original wrtten tasks with a text contents in input textboxes when I finish editing.
So, I would like you to tell me how to write a "compEdit" function in the source code below.
2nd
When I add several tasks and push an edit button of other than 1st task, too many input text boxes are created.Probably, the number of created textboxes is as same amount as the element in arrayItems.
I suppose using map method itself is a wrong aproach.But I can't come up with a good alternative.
I'll be glad if someone tell me a proper way and why the bug in 2nd question happens.
Source code is here
//grab the elements
const todoText = document.getElementsByClassName('todo-text')[0];
const todoBtn = document.getElementsByClassName('todo-btn')[0];
const inputTask = document.getElementsByClassName('input-task')[0];
const arrayItems = [];
//function to add tasks
const addTask = (task) => {
const listItem = document.createElement('li');
const showItem = inputTask.appendChild(listItem);
showItem.innerHTML = task;
listItem.classList.add('list-item');
arrayItems.push(listItem);
//create a delete button
const deleteBtn = document.createElement('button');
deleteBtn.innerHTML = 'delete';
listItem.appendChild(deleteBtn);
//call a function when the button will be clicked
deleteBtn.addEventListener('click', () => {
deleteTask(deleteBtn);
});
//create an edit button
const editBtn = document.createElement('button');
editBtn.innerHTML = 'edit';
listItem.appendChild(editBtn);
//call a function when the button will be clicked
editBtn.addEventListener('click', () => {
editTask(arrayItems, listItem);
});
};
const deleteTask = (deleteBtn) => {
const chosenItem = deleteBtn.closest('li');
inputTask.removeChild(chosenItem);
};
const editTask = (els = [], inputTask) => {
//create a textbox into list items
inputTask.innerHTML = els.map((el, i) => {
return `
<input type="text" class="editing-text[${i}]" name="item[${i}]" required>
<input type="submit" class="complete-btn" value="complete">
`
});
//grab the elements of "edit button" and text into it
const editingText = document.getElementsByClassName('editing-text')[0];
const compBtn = document.getElementsByClassName('complete-btn')[0];
//the function to complete editing
const compEdit = () => {
}
compBtn.addEventListener('click', compEdit);
}
todoBtn.addEventListener('click', () => {
const task = todoText.value;
if(task == ''){
return;
}
addTask(task);
todoText.value = '';
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="/style.css">
</head>
<body>
<div class="wrap">
<header class="header">
<h1>Welcome!</h1>
</header>
<section class="add-todo">
<div class="list-title">
<h2>Add your task</h2>
</div>
<div class="contents-wrapper">
<div class="list-contents">
<input type="text" name="todo" class="todo-text">
<input type="submit" value="add" class="todo-btn">
</div>
</div>
</section>
<section class="current-tasks">
<div class="current-tasks__title">
<h3>current tasks</h3>
</div>
<div class="tasks-wrapper">
<ul class="input-task"></ul>
</div>
</section>
<footer></footer>
</div>
<script src="/main.js"></script>
</body>
</html>

When I add several tasks and push an edit button of other than 1st task, too many input text boxes are created
This is happening because as you add tasks, the number of elements are increasing, so the inputs are created on the basis of the number of li elements currently in the document. You can avoid this by using event.target which can be used to target each task element. I have shown an example with slight modification in your code.
//grab the elements
const todoText = document.getElementsByClassName("todo-text")[0];
const todoBtn = document.getElementsByClassName("todo-btn")[0];
const inputTask = document.getElementsByClassName("input-task")[0];
//function to add tasks
const addTask = (task) => {
const listItem = document.createElement("li");
const showItem = inputTask.appendChild(listItem);
const taskElem = document.createElement("span");
taskElem.innerHTML = task;
listItem.appendChild(taskElem);
listItem.classList.add("list-item");
//create a delete button
const deleteBtn = document.createElement("button");
deleteBtn.innerHTML = "delete";
listItem.appendChild(deleteBtn);
//call a function when the button will be clicked
deleteBtn.addEventListener("click", () => {
deleteTask(deleteBtn);
});
//create an edit button
const editBtn = document.createElement("button");
editBtn.innerHTML = "edit";
// add a class to identify
editBtn.classList.add("edit");
listItem.appendChild(editBtn);
//call a function when the button will be clicked
// editBtn.addEventListener("click", () => {
// // editTask(arrayItems, listItem);
// });
};
const deleteTask = (deleteBtn) => {
const chosenItem = deleteBtn.closest("li");
inputTask.removeChild(chosenItem);
};
inputTask.addEventListener("click", function(e) {
const target = e.target.classList.contains("edit"),
update = e.target.classList.contains("update");
if (target) {
let val = e.target.parentElement.firstChild.innerHTML;
// alert(val);
e.target.parentElement.innerHTML = `
<input type="text" name="todo" class="todo-text" value="${val}">
<input type="submit" value="update" class="todo-btn update">
`;
}
if (update) {
let updatedValue = e.target.previousElementSibling.value;
e.target.parentElement.innerHTML = `
<li class="list-item"><span>${updatedValue}</span><button>delete</button><button class="edit">edit</button></li>
`;
}
});
todoBtn.addEventListener("click", () => {
const task = todoText.value;
if (task == "") {
return;
}
addTask(task);
todoText.value = "";
});
<div class="wrap">
<header class="header">
<h1>Welcome!</h1>
</header>
<section class="add-todo">
<div class="list-title">
<h2>Add your task</h2>
</div>
<div class="contents-wrapper">
<div class="list-contents">
<input type="text" name="todo" class="todo-text">
<input type="submit" value="add" class="todo-btn">
</div>
</div>
</section>
<section class="current-tasks">
<div class="current-tasks__title">
<h3>current tasks</h3>
</div>
<div class="tasks-wrapper">
<ul class="input-task"></ul>
</div>
</section>
<footer></footer>
</div>

Related

Why is the done button not working properly?

Apparently I'm trying to create a todo list where I can ofcourse add and remove the tasks. Adding tasks works fine; however clicking on the Done Button works but doesn't do what I want it to do. Basically I have a Logical Error, but I don't know what to do to fix it.
The Code
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>To-Do List</h1>
<form id="todoForm">
<input id="todoInput" />
<button type="button" onclick="todoList()">New</button>
<button type="button" onclick="">Retrieve</button>
</form>
<ol id="todoList"></ol>
<script>
var todos = []; //Problem is from here
var removed = [];
function todoList() {
var item = document.getElementById("todoInput").value;
todos.push(item);
var text = document.createTextNode(item);
var newItem = document.createElement("li");
newItem.innerHTML = item + ' <button id="Done">Done</button>';
document.getElementById("todoList").appendChild(newItem);
const donebtn = document.getElementById("Done");
donebtn.addEventListener("click", function() {
removetodo(newItem, item)
});
}
function removetodo(item, tasktext) {
const tasklist = document.getElementById("todoList");
tasklist.removeChild(item);
removed.push(tasktext);
}
</script>
</body>
</html>
Thing is, I tried finding solutions to it on Google and other places; yet, I still didnt know how to fix it. I dont want to just change the whole code so it could work. I specifically wanted it in the way I wrote it in
newItem.innerHTML = item + ' Done'; I changed this line the problem was that you are assigning the same id's to all done so I used a count variable which is at the start 0 when you run function if will 0 like done0 when the function run it will increase count++ will increase it next time it will be done1 so your code will work correctly
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>To-Do List</h1>
<form id="todoForm">
<input id="todoInput" />
<button type="button" onclick="todoList()">New</button>
<button type="button" onclick="">Retrieve</button>
</form>
<ol id="todoList"></ol>
<script>
var todos = []; //Problem is from here
var removed = [];
let count = 0;
function todoList() {
var item = document.getElementById("todoInput").value;
todos.push(item);
var text = document.createTextNode(item);
var newItem = document.createElement("li");
newItem.innerHTML = item + ' <button id="Done'+count+'">Done</button>';
document.getElementById("todoList").appendChild(newItem);
const donebtn = document.getElementById("Done"+count);
donebtn.addEventListener("click", function(){
removetodo(newItem, item)
});
count++;
}
function removetodo(item, tasktext) {
const tasklist = document.getElementById("todoList");
tasklist.removeChild(item);
removed.push(tasktext);
}
</script>
</body>
</html>
one more suggestion
newItem.innerHTML = item + ' <button id="Done'+count+'">Done</button>';
document.getElementById("todoList").appendChild(newItem);
const donebtn = document.getElementById("Done"+count);
donebtn.addEventListener("click", function(){
here in your code const donebtn = document.getElementById("Done"+count); you don't need this line just donebtn.addEventListener("click", function(){ here insted of donebtn you can use newItem.addEventListener and then append it
document.getElementById("todoList").appendChild(newItem); at the last use this.
newItem.innerHTML = item + ' <button id="Done'+count+'">Done</button>';
newItem.addEventListener("click", function(){}
document.getElementById("todoList").appendChild(newItem);
like this
This code will only run when your function is called.
const donebtn = document.getElementById("Done");
donebtn.addEventListener("click", function() {
removetodo(newItem, item)
});
you should put it outside the functions to attach the listener.
The first issue with the code is that when you remove the task from the list, it's not actually removing it from the todos array. To fix this, you can add the following line after removing the task from the list:
todos.splice(todos.indexOf(tasktext), 1);
The second issue is that you are using the same id for all the "Done" <button> elements, in the HTML markup, IDs should be unique. So when you use document.getElementById("Done"), it always returns the first element with that id.
To fix this issue, you can use a class instead of an id and query for all elements with that class and attach an event listener to each button individually.
Updated code:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>To-Do List</h1>
<form id="todoForm">
<input id="todoInput" />
<button type="button" onclick="todoList()">New</button>
<button type="button" onclick="">Retrieve</button>
</form>
<ol id="todoList"></ol>
<script>
var todos = [];
var removed = [];
function todoList() {
let item = document.getElementById("todoInput").value;
todos.push(item);
let text = document.createTextNode(item);
let newItem = document.createElement("li");
newItem.innerHTML = item + ' <button class="doneBtn">Done</button>';
document.getElementById("todoList").appendChild(newItem);
const donebtn = newItem.getElementsByClassName("doneBtn")[0];
donebtn.addEventListener("click", function() {
removetodo(newItem, item);
});
}
function removetodo(item, tasktext) {
const tasklist = document.getElementById("todoList");
tasklist.removeChild(item);
removed.push(tasktext);
todos.splice(todos.indexOf(tasktext), 1);
}
</script>
</body>
</html>
Each time a new task is added, all the "Done" buttons have the same id, which is not allowed in HTML as id values must be unique within a page. This means that only the first "Done" button will respond to the click event, and all the others will be ignored.
One way you can try is to store the task text in a data attribute of the "Done" button, and use it in the removetodo function to identify the task to remove like so ...
<!DOCTYPE html>
<html lang="en">
<head>
<title>Document</title>
</head>
<body>
<h1>To-Do List</h1>
<form id="todoForm">
<input id="todoInput" />
<button type="button" onclick="todoList()">New</button>
<button type="button" onclick="">Retrieve</button>
</form>
<ol id="todoList"></ol>
<script>
var todos = [];
var removed = [];
function todoList() {
var item = document.getElementById("todoInput").value;
todos.push(item);
var text = document.createTextNode(item);
var newItem = document.createElement("li");
newItem.innerHTML = item + ' <button class="Done">Done</button>';
document.getElementById("todoList").appendChild(newItem);
const donebtn = newItem.getElementsByClassName("Done")[0];
donebtn.addEventListener("click", function() {
removetodo(newItem, item)
});
donebtn.setAttribute("data-task", item);
}
function removetodo(item, tasktext) {
const tasklist = document.getElementById("todoList");
tasklist.removeChild(item);
removed.push(tasktext);
}
</script>
</body>

Setting a value in html using buttons generated from an Apps Script / javascript array

I am trying to piece together a Google Apps script for a touchscreen clocking in system, and that involves generating some buttons from an array taken from a spreadsheet, but I'm getting a bit lost working out how to get the script to document which of these automatically generated buttons has been pressed.
Basically, I am using a modified version of this script (https://www.youtube.com/watch?v=KGhGWuTjJwc) - I need it to work with a touch screen.
I have got a version of the script given in the video above working. But because the web app must work on a touch screen I need to be able to generate buttons for the input of staff ID and PIN to replace the text boxes.
To do this I am pulling in an array from a Google Sheet that contains all staff initials needed to log in, as well as adding a numeric keypad to enter a PIN.
I have (sort of) successfully borrowed a keypad from here:https://github.com/ProgrammingHero1/batch5-pin-matcher-solution but I am stuck trying to get use buttons for the staff ID input.
I have managed to generate the buttons from the spreadsheet array, using a modified version of this Create an array of buttons from Javascript array but I can't work out how to set staffid to match whichever of the auto-generated buttons was pressed last. Currently those buttons don't do anything.
If anyone can help guide me the last step of the way so that staffid is set using the buttons and not using the text box that would be very much appreciated.
Below is the code I am using. I am aware that it is a dog's breakfast - that's because I am hacking it together from various sources working at (well, realistically well beyond) the limits of my understanding!
Anyway, here is the HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<!-- Metro 4 -->
<link rel="stylesheet" href="https://cdn.metroui.org.ua/v4/css/metro-all.min.css">
<style>
.main-box {
max-width:500px;
}
.error-message {
background:red;
color:white
padding: 1000px;
border-radius: 1000px;
}
</style>
</head>
<body>
<div class="container">
<div class="container d-flex flex-justify-center pt-9">
<div data-role="panel" class="main-box">
<form id="main-form">
<div class="form-group">
<input type="text" data-role="input" data-prepend="Staff ID" id="staffid">
<div class="form-group">
</div>
<div class="form-group">
<button id="start-work" class="button success" type="submit" data-action="Start work">Start work</button>
<button id="finish-work" class="button success" type="submit" data-action="Finish work">Finish work</button>
<button id="start-break" class="button success" type="submit" data-action="Start break">Start break</button>
<button id="finish-break" class="button success" type="submit" data-action="Finish break">Finish break</button>
<div class="input-section half-width">
<input id="typed-numbers" class="form-control" type="text">
<div class="numbers">
<div id="key-pad" class="calc-body">
<div class="calc-button-row">
<div class="button">7</div>
<div class="button">8</div>
<div class="button">9</div>
</div>
<div class="calc-button-row">
<div class="button">4</div>
<div class="button">5</div>
<div class="button">6</div>
</div>
<div class="calc-button-row">
<div class="button">1</div>
<div class="button">2</div>
<div class="button">3</div>
</div>
<div class="calc-button-row">
<div class="button"><</div>
<div class="button">0</div>
<div class="button">C</div>
</div>
</div>
</div>
</div>
</div>
</form>
<div id="message" class="d-none error-message mt4">
Error!!
</div>
</div>
</div>
</body>
<!-- Metro 4 -->
<script src="https://cdn.metroui.org.ua/v4/js/metro.min.js"></script>
<script>
const TSPwebapp = {}
TSPwebapp.onLoad = function(){
TSPwebapp.form = document.getElementById("main-form")
TSPwebapp.staffidInput = document.getElementById("staffid")
TSPwebapp.pinInput = document.getElementById("typed-numbers")
TSPwebapp.startWorkButton = document.getElementById("start-work")
TSPwebapp.finishWorkButton = document.getElementById("finish-work")
TSPwebapp.startBreakButton = document.getElementById("start-break")
TSPwebapp.finishBreakButton = document.getElementById("finish-break")
TSPwebapp.message = document.getElementById("message")
TSPwebapp.form.addEventListener("submit",TSPwebapp.onSubmit)
TSPwebapp.startWorkButton.addEventListener("click",TSPwebapp.startFinishWork)
TSPwebapp.finishWorkButton.addEventListener("click",TSPwebapp.startFinishWork)
TSPwebapp.startBreakButton.addEventListener("click",TSPwebapp.startFinishBreak)
TSPwebapp.finishBreakButton.addEventListener("click",TSPwebapp.startFinishBreak)
} // TSPwebapp.onLoad function
TSPwebapp.onSubmit= function(e){
e.preventDefault()
} // TSPwebapp.onSubmit function
TSPwebapp.startFinishWork = function(e){
const payload = {
staffid: TSPwebapp.staffidInput.value,
pin: TSPwebapp.pinInput.value,
action: e.target.dataset.action
}
google.script.run.withSuccessHandler(() => {
TSPwebapp.staffidInput.value = ""
TSPwebapp.pinInput.value = ""
} ).withFailureHandler(() => {
TSPwebapp.message.classList.remove("d-none")
setTimeout(() => {TSPwebapp.message.classList.add("d-none")},5000)
}).startFinishWork(payload)
} // TSPwebapp.startFinishWork function
TSPwebapp.startFinishBreak = function(e){
const payload = {
staffid: TSPwebapp.staffidInput.value,
pin: TSPwebapp.pinInput.value,
action: e.target.dataset.action
}
google.script.run.withSuccessHandler(() => {
TSPwebapp.staffidInput.value = ""
TSPwebapp.pinInput.value = ""
} ).withFailureHandler(() => {
TSPwebapp.message.classList.remove("d-none")
setTimeout(() => {TSPwebapp.message.classList.add("d-none")},5000)
}).startFinishBreak(payload)
} // TSPwebapp.startFinishBreak function
</script>
<script>
document.getElementById('key-pad').addEventListener('click', function (event) {
const number = event.target.innerText;
const calcInput = document.getElementById('typed-numbers');
if (isNaN(number)) {
if (number == 'C') {
calcInput.value = '';
}
}
else {
const previousNumber = calcInput.value;
const newNumber = previousNumber + number;
calcInput.value = newNumber;
}
});
</script>
<script>
document.addEventListener("DOMContentLoaded",TSPwebapp.onLoad)
document.addEventListener("DOMContentLoaded",function(){
google.script.run.withSuccessHandler(printBtn).useDataRange();
});
function printBtn(staffData) {
for (var i = 0; i < staffData.length; i++) {
var btn = document.createElement("button");
var t = document.createTextNode(staffData[i]);
btn.appendChild(t);
document.body.appendChild(btn);
}
}
window.onload = printBtn();
</script>
</body>
</html>
Here is the Google Apps Script code:
function doGet(e) {
Logger.log(e);
return HtmlService.createHtmlOutputFromFile("form");
}
function useDataRange () {
const ss = SpreadsheetApp.getActiveSpreadsheet()
const wsStaff = ss.getSheetByName("Staff")
const staffData = wsStaff.getRange(2,2,wsStaff.getLastRow()-1,1).getValues()
Logger.log(staffData)
return staffData;
}
function startFinishBreak(payload){
console.log(payload)
if (!["Start work","Finish work","Start break","Finish break"].includes(payload.action)){
throw new Error("Sign in or sign out failed")
return
}
console.log("Initial check passed")
const ss = SpreadsheetApp.getActiveSpreadsheet()
const wsBreakData = ss.getSheetByName("Break data")
const wsStaff = ss.getSheetByName("Staff")
const staffData = wsStaff.getRange(2,2,wsStaff.getLastRow()-1,3).getValues()
const matchingStaff = staffData.filter(r => r[0].toString() === payload.staffid && r[2].toString() === payload.pin)
if(matchingStaff.length !== 1){
throw new Error("Sign in or sign out failed")
return
}
const idsData = wsBreakData.getRange(2,2,wsBreakData.getLastRow()-1,3).getValues()
console.log(idsData)
const matchingIdsData = idsData.filter(r => r[0].toString() === payload.staffid)
console.log(matchingIdsData)
const latestAction = matchingIdsData.length === 0 ? "Finish break" : matchingIdsData[matchingIdsData.length-1][2]
if (latestAction === payload.action){
throw new Error("Sign in or sign out failed")
return
}
wsBreakData.appendRow([new Date(),payload.staffid,payload.pin,payload.action])
}
function startFinishWork(payload){
console.log(payload)
if (!["Start work","Finish work","Start break","Finish break"].includes(payload.action)){
throw new Error("Sign in or sign out failed")
return
}
console.log("Initial check passed")
const ss = SpreadsheetApp.getActiveSpreadsheet()
const wsWorkData = ss.getSheetByName("Work data")
const wsStaff = ss.getSheetByName("Staff")
const staffData = wsStaff.getRange(2,2,wsStaff.getLastRow()-1,3).getValues()
const matchingStaff = staffData.filter(r => r[0].toString() === payload.staffid && r[2].toString() === payload.pin)
if(matchingStaff.length !== 1){
throw new Error("Sign in or sign out failed")
return
}
const idsData = wsWorkData.getRange(2,2,wsWorkData.getLastRow()-1,3).getValues()
console.log(idsData)
const matchingIdsData = idsData.filter(r => r[0].toString() === payload.staffid)
console.log(matchingIdsData)
const latestAction = matchingIdsData.length === 0 ? "Finish work" : matchingIdsData[matchingIdsData.length-1][2]
if (latestAction === payload.action){
throw new Error("Sign in or sign out failed")
return
}
wsWorkData.appendRow([new Date(),payload.staffid,payload.pin,payload.action])
}
I hope this description all more or less makes sense - I am trying something a way beyond by current capabilities but I do need to get this task done and hopefully I'm learning in the process.
You need to add a value and event listener to each button. Then you can use the value to determine which button was pressed.
I have updated my script to address the comments below.
First add a new division.
<div id="staffButtons">
</div>
<div id="message" class="d-none error-message mt4">
Next make some changes to original script as shown.
function printBtn(staffData) {
let div = document.getElementById("staffButtons"); // add this
for (var i = 0; i < staffData.length; i++) {
var btn = document.createElement("button");
var t = document.createTextNode(staffData[i]);
btn.value = staffData[i]
btn.addEventListner("click",buttonClick);
btn.appendChild(t);
div.appendChild(btn); // change this
}
}
function buttonClick() {
document.getElementById("staffid") = this.value;
}
Reference
addEventListener

Updating an array without index

I was unsure how exactly to phrase this in the title. I've made a todo list and I'm working on making the todo items editable. Through the displayTodo function, I've been able to make the li items editable in the DOM, but I would like this change to be reflected in the todoList array as well when I hit the save button. I'm unsure of how exactly I would be able to make this work. I was thinking of the splice method, but I don't know how that would work in this situation since I would need to pass in the index.
// Global Variables
const input = document.querySelector('.input');
const addBtn = document.querySelector('.add-btn');
const removeBtn = document.querySelector('.remove-btn');
const todos = document.querySelector('.todos');
// Event Listeners
addBtn.addEventListener('click', addTodo);
removeBtn.addEventListener('click', removeTodo);
const todoList = [
]
function addTodo() {
// Push user input to array
let inputValue = input.value;
todoList.push(inputValue);
displayTodo();
input.value = '';
console.log(todoList);
}
function removeTodo() {
let listItems = document.querySelectorAll('.todos li');
// Remove last todo from array
todoList.splice(-1, 1);
// Remove last todo from ul
todos.removeChild(listItems[listItems.length - 1]);
//console.log(todoList);
}
function displayTodo() {
// Create li and display it
let newTodo = document.createElement('li');
newTodo.textContent = input.value;
todos.appendChild(newTodo);
// Create edit button and display it
let editButton = document.createElement('button');
editButton.textContent = 'Edit';
newTodo.appendChild(editButton);
editButton.addEventListener('click', function() {
// Create edit input and save button
editButton.style.opacity = 0;
editButton.style.visibility = 'hidden';
let editInput = document.createElement('input');
newTodo.appendChild(editInput);
let saveButton = document.createElement('button');
newTodo.appendChild(saveButton);
saveButton.textContent = 'Save';
saveButton.addEventListener('click', function() {
newTodo.textContent = editInput.value;
console.log(todoList);
})
});
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" type="text/css" href="style.css">
<title>Todo List</title>
</head>
<body>
<div class="container">
<h1>Todo List</h1>
<input class="input" type="text" placeholder="Add A Task" autocomplete="off" required>
<button class="add-btn">Add Task</button>
<button class="remove-btn">Remove Task</button>
<ul class="todos">
</ul>
</div>
</body>
</html>
First of all, In editButton.addEventListener('click', function() {}, get the text content of the <li> element that has to be edited. The text content has the word 'Edit' appended to the list element and hence removing it in the second line. Get the index of the array element whole value is liValue using indexOf property.
let liValue = newTodo.textContent;
liValue = liValue.replace('Edit', '');
let liIndex = todoList.indexOf(liValue);
In saveButton.addEventListener('click', function () {}, after updating the DOM, use splice() to update the array list.
todoList.splice(liIndex, 1, editInput.value);
I have added the function in which the changes are done. The parts of the code that has to be added are commented down below.
editButton.addEventListener('click', function () {
// Create edit input and save button
editButton.style.opacity = 0;
editButton.style.visibility = 'hidden';
/* first part of the code starts here */
let liValue = newTodo.textContent;
liValue = liValue.replace('Edit', '');
let liIndex = todoList.indexOf(liValue);
/* first part of the code ends here */
let editInput = document.createElement('input');
newTodo.appendChild(editInput);
let saveButton = document.createElement('button');
newTodo.appendChild(saveButton);
saveButton.textContent = 'Save';
saveButton.addEventListener('click', function () {
newTodo.textContent = editInput.value;
/* second part of the code starts here */
todoList.splice(liIndex, 1, editInput.value);
/* second part of the code ends here */
})
});
Link to codepen: https://codepen.io/geekyquentin/pen/LYQdjXw

How to delete one button when deleting last to-do list item (JavaScript)

I'm creating a to-do list and I want my CLEAR ITEMS button to be deleted once I delete the last item on the list (now it doesn't disappear unless I refresh the page). How can I achieve this? Any suggestions? I've tried different solutions but I really don't know how to make it work. I'm really stuck at this.
JavaScript code:
const toDoItems = document.getElementsByClassName("to-do-items")[0];
const input = document.getElementById("input");
const trashIcon = document.getElementById("trash");
const delItems = document.getElementsByClassName("clear-items")[0];
input.addEventListener("keydown", function (event) {
if (event.key === "Enter") {
addItem();
clearItems();
}
});
function addItem() {
let divParent = document.createElement("div");
let divChild = document.createElement("div");
let checkIcon = document.createElement("i");
let trashIcon = document.createElement("i");
divParent.className = "item";
divParent.innerHTML = "<div>" + input.value + "</div>";
checkIcon.className = "fas fa-check-square";
checkIcon.style.color = "lightgray";
checkIcon.addEventListener("mouseenter", function () {
checkIcon.style.color = "limegreen";
});
checkIcon.addEventListener("mouseleave", function () {
checkIcon.style.color = "lightgray";
});
checkIcon.addEventListener("click", function () {
checkIcon.style.color = "green";
divParent.style.textDecoration = "line-through";
checkIcon.addEventListener("mouseleave", function () {
checkIcon.style.color = "green";
});
});
divChild.appendChild(checkIcon);
trashIcon.className = "fas fa-trash";
trashIcon.style.color = "darkgray";
trashIcon.addEventListener("mouseenter", function () {
trashIcon.style.color = "rgb(182, 71, 71)";
});
trashIcon.addEventListener("mouseleave", function () {
trashIcon.style.color = "darkgray";
});
trashIcon.addEventListener("click", function () {
divParent.remove();
if (toDoItems == 1) {
delItems.remove();
}
});
divChild.appendChild(trashIcon);
divParent.appendChild(divChild);
toDoItems.appendChild(divParent);
input.value = "";
}
let clearButton = false;
function clearItems() {
let clear = document.createElement("button");
if (clearButton === false) {
clear.innerHTML = "Clear Items";
clear.className = "btn";
delItems.appendChild(clear);
input.removeEventListener("click", clearItems);
}
clearButton = true;
document
.getElementsByTagName("button")[1]
.addEventListener("click", function () {
window.location.reload();
});
}
Here's the HTML code:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="stylesheet" href="style.css" />
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"
integrity="sha512-KfkfwYDsLkIlwQp6LFnl8zNdLGxu9YAA1QvwINks4PhcElQSvqcyVLLD9aMhXd13uQjoXtEKNosOWaZqXgel0g=="
crossorigin="anonymous"
referrerpolicy="no-referrer"
/>
<title>To Do List</title>
</head>
<body>
<div class="container">
<div class="nav">
<h2><i class="fa-solid fa-clipboard-check"></i> To-do List</h2>
<div class="user-input">
<input id="input" type="text" /><button
onclick="addItem(), clearItems()"
>
Submit
</button>
</div>
</div>
</div>
<div class="container">
<div class="to-do-items"></div>
<div class="clear-items"></div>
</div>
<script src="script.js"></script>
</body>
</html>
Every time you delete something. Check how many items are left. If that amount is 0 remove the clear all button. If you press the clear all button. Make sure at the end of the code that clears all the items you also remove the button.
you can use element.remove() to get rid of the button. More info here.
I would also use document.getElementById() to get the button (maybe items too) itself. More info on that here.

To-Do list saving items to database using ajax

I have a to-do list that kinda works, but when the page refreshed all of the added items get removed.
At first I tried using local storage to store and then retrieve the items, but I couldn't get that to work. Then I remembered about ajax, but I'm still a beginner and am not familiar with it.
I couldn't find a solution that works, but any tips would be much appreciated.
Html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="styles.css">
<link href="https://fonts.googleapis.com/css2?family=Poppins&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/5.14.0/css/all.min.css"
integrity="sha512-1PKOgIY59xJ8Co8+NE6FZ+LOAZKjy+KY8iq0G4B3CyeY6wYHN3yt9PW0XpSriVlkMXe40PTKnXrLnZ9+fkDaog=="
crossorigin="anonymous">
<title>Shopping List</title>
</head>
<body>
<a href="logout.php">
<button class="logout">Logout</button>
</a>
<header>
<h1>Shopping List</h1>
</header>
<form>
<input type="text" placeholder="Enter products" class="todo_input" />
<button class="todo_button" type="submit">
<i class="fas fa-plus-square"></i>
</button>
<div class="select">
<select name="todos" class="filter_todo">
<option value="all">All</option>
<option value="completed">In cart</option>
<option value="uncompleted">Not in cart</option>
</select>
</div>
</form>
<div class="todo_container">
<ul class="todo_list">
<div class="todo">
<li class="todo_item">Tomatoes</li>
<button class="complete_btn"><i class="fas fa-check"></i></button>
<button class="delete_btn"><i class="fas fa-trash"></i></button>
</div>
</ul>
</div>
<script src="script.js" type="application/javascript"></script>
</body>
</html>
Javascript:
//selectors
const todoInput = document.querySelector('.todo_input');
const todoButton = document.querySelector('.todo_button');
const todoList = document.querySelector('.todo_list');
const filterOption = document.querySelector('.filter_todo');
//event listeners
todoButton.addEventListener("click", addTodo)
todoList.addEventListener("click", deleteCheck)
filterOption.addEventListener("click", filterTodo)
//functions
function addTodo(event) {
event.preventDefault();
//todo DIV
const todoDiv = document.createElement('div');
todoDiv.classList.add('todo');
//todo LI
const newTodo = document.createElement('li');
newTodo.innerText = todoInput.value;
newTodo.classList.add('todo_item');
todoDiv.appendChild(newTodo);
if(todoInput.value === ""){
return null
}
//check mark BUTTON
const completedButton = document.createElement('button');
completedButton.innerHTML = '<i class="fas fa-check"></i>';
completedButton.classList.add('complete_btn')
todoDiv.appendChild(completedButton);
//delete BUTTON
const deleteButton = document.createElement('button');
deleteButton.innerHTML = '<i class="fas fa-trash"></i>';
deleteButton.classList.add('delete_btn')
todoDiv.appendChild(deleteButton);
//Append to Actual LIST
todoList.appendChild(todoDiv);
//Clear todo input VALUE
todoInput.value = ""
}
//DELETE & CHECK
function deleteCheck(e) {
const item = e.target;
//DELETE ITEM
if (item.classList[0] === "delete_btn") {
const todo = item.parentElement;
//ANIMATION TRANSITION
todo.classList.add("fall")
todo.addEventListener('transitionend', function () {
todo.remove()
})
}
//COMPLETE ITEM
if (item.classList[0] === "complete_btn") {
const todo = item.parentElement;
todo.classList.toggle("completedItem")
}
}
//FILTERING THE TASKS ACCORDING THE OPTION
function filterTodo(e) {
const todos = todoList.childNodes;
for(let i = 1; i<todos.length; i++ ){
switch (e.target.value) {
case "all":
todos[i].style.display = "flex";
break;
case "completed":
if (todos[i].classList.contains('completedItem')) {
todos[i].style.display = "flex";
} else {
todos[i].style.display = "none";
}
break;
case "uncompleted":
if (!todos[i].classList.contains('completedItem')) {
todos[i].style.display = "flex";
} else {
todos[i].style.display = "none";
}
break;
}
}
}
You can use ajax as an option to send requests to save your data in you Database and get your records to fill the list for example.
the syntax is a little bit simple:
var data = ($("#YOUR_HTML_FORM_ID").serialize());
$.ajax({
url: 'YOUR_API_ROUTE',
data: data,
processData: false,
type: 'POST',
success: function ( data ) {
// All good here, do something like show a success message
},
error: function (data) {
data = JSON.parse(data.responseText);
// something went wrong
}
});

Categories