简体   繁体   中英

How do I handle multiple created buttons with JavaScript in a ToDo web script that all have the same class name?

I am making a simple ToDo app that when you write in the input form and submit it, it posts it neatly in a flex-box design below.

After it adds Your writing to the ToDo list at the bottom, JavaScript clears the input selection box.

My problem is that all the created ToDo list items are the SAME! They have the same class name and structure. I do not know how to handle all the buttons that are created so that when you click on the <button class='delete-btn'>x</button> it deletes only that button.

I have put all the writing templates created into a simple array called arrayOfText .

I was hoping I could delete the specific <div class='todo-div'>...</div> that the button was clicked from and then rewrite the whole .innerHTML of the ToDo list section.

This basically updates it and removes the div from the ToDo list that the button was clicked from, but I cannot seem to get it to work.

If you need more information, please message me.

在此处输入图像描述

 "use strict"; const outputSection = document.querySelector("#output-section"); outputSection.innerHTML = ""; const writingArea = document.querySelector("#writing-area"); const publishBtn = document.querySelector(".default-btn"); const deleteBtns = document.getElementsByClassName("delete-btn"); const allToDoDivs = document.getElementsByClassName("todo-div"); const arrayOfText = []; const cutAndPrintFunc = function (e) { e.preventDefault(); //take writing in and print it to the current agenda // clear the writing area if (writingArea.value != "") { const date = new Date(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDay()).padStart(2, "0"); const year = date.getFullYear(); const hour = date.getHours() > 12 ? date.getHours() - 12 : date.getHours(); const AMorPM = date.getHours() > 12 ? "PM" : "AM"; const minute = String(date.getMinutes()).padStart(2, "0"); const template = ` <div class="todo-div"> <h1 class="text-content">${writingArea.value}</h1> <button class="delete-btn">x</button> <p class="date-p">${month}/${day}/${year} --- requested @ ${hour}:${minute} ${AMorPM} </p> </div>`; arrayOfText.push(template); outputSection.insertAdjacentHTML("beforeend", template); writingArea.value = ""; Array.from(allToDoDivs).forEach((el, ind) => { if (ind % 2 === 0) { el.style.backgroundColor = "#3ce815"; el.lastElementChild.style.color = "black"; } //-----this does not work // Array.from(allToDoDivs)[ // allToDoDivs.length - 1 // ].children[1].addEventListener("click", () => { // console.log(this); // // arrayOfText.pop(this); // // outputSection.innerHTML = arrayOfText.join(""); // }); }); } }; //publish text by hitting enter or pressing the plus sign in textbox publishBtn.addEventListener("click", cutAndPrintFunc);
 <!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="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Comfortaa&display=swap" rel="stylesheet" /> <link rel="stylesheet" href="/style.css" type="text/css" /> <title>Griffin's ToDo List</title> </head> <body> <header> <h1> Welcome to <em style="text-decoration: underline">Griffin's</em> To-Do List </h1> <div id="mini-flex-div"> <div class="ball" id="blue">&nbsp;</div> <div class="ball" id="orange">&nbsp;</div> <div class="ball" id="purple">&nbsp;</div> <p>What needs to be done today...</p> <div class="ball" id="purple">&nbsp;</div> <div class="ball" id="orange">&nbsp;</div> <div class="ball" id="blue">&nbsp;</div> </div> </header> <main> <div id="writer-div"> <form> <input id="writing-area" type="text" rows="1" placeholder="Lets get this out of the way..." maxlength="50" spellcheck="true" autofocus ></input> <button class='default-btn'>+</button> </form> </div> </main> <div id="bottom-header"> <h1 id="output-h1">The current agenda...<hr id="splitter"></h1> </div> <section id="output-section"> <div class="todo-div"> <h1 class="text-content">Mow the lawn</h1> <button class="delete-btn">x</button> <p class="date-p">mm/dd/yyyy</p> </div> <div class="todo-div"> <h1 class="text-content">Mow the lawn</h1> <button class="delete-btn">x</button> <p class="date-p">mm/dd/yyyy</p> </div> </section> <script src="/toDo.js"></script> </body> </html>

There are really only rare cases where you want to manipulate the DOM through HTML. So using insertAdjacentHTML and innerHTML is most of the time not what you want to do.

Use createElement , appendChild and removeChild instead.

For the delete button, you can use event delegation , and find the todo div that corresponds to the button using closest .

Alternating coloring per row can be done with a CSS rule.

Using all this you will have a code like that:

 "use strict"; const outputSection = document.querySelector("#output-section"); outputSection.innerHTML = ""; const writingArea = document.querySelector("#writing-area"); const publishBtn = document.querySelector(".default-btn"); const cutAndPrintFunc = function(e) { e.preventDefault(); //take writing in and print it to the current agenda // clear the writing area if (writingArea.value != "") { const date = new Date(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDay()).padStart(2, "0"); const year = date.getFullYear(); const hour = date.getHours() > 12 ? date.getHours() - 12 : date.getHours(); const AMorPM = date.getHours() > 12 ? "PM" : "AM"; const minute = String(date.getMinutes()).padStart(2, "0"); // create an actual div element using createElement const todoItem = document.createElement('div') // add the todo-div class to it todoItem.classList.add('todo-div') // here you can use innerHTML, but you still might want to // avoid its usage in general todoItem.innerHTML = ` <h1 class="text-content">${writingArea.value}</h1> <button class="delete-btn">x</button> <p class="date-p">${month}/${day}/${year} --- requested @ ${hour}:${minute} ${AMorPM} </p> `; // append the created div element to the outputSection outputSection.appendChild(todoItem); writingArea.value = ""; } }; //publish text by hitting enter or pressing the plus sign in textbox publishBtn.addEventListener("click", cutAndPrintFunc); // we attach an event listener on outputSection for click outputSection.addEventListener("click", (evt) => { // only handle the click if it happend on the delete button if (evt.target.matches('.delete-btn')) { evt.preventDefault(); // At this point the evt.target is the delete button the // click happened on so you need search for the // ascendant that represents the todo-div using closest // and remove that element from outputSection outputSection.removeChild(evt.target.closest('.todo-div')) } })
 /* use the odd rule to style all odd todo-div elements */ .todo-div:nth-child(odd) { background-color: #3ce815; }
 <!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="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Comfortaa&display=swap" rel="stylesheet" /> <link rel="stylesheet" href="/style.css" type="text/css" /> <title>Griffin's ToDo List</title> </head> <body> <header> <h1> Welcome to <em style="text-decoration: underline">Griffin's</em> To-Do List </h1> <div id="mini-flex-div"> <div class="ball" id="blue">&nbsp;</div> <div class="ball" id="orange">&nbsp;</div> <div class="ball" id="purple">&nbsp;</div> <p>What needs to be done today...</p> <div class="ball" id="purple">&nbsp;</div> <div class="ball" id="orange">&nbsp;</div> <div class="ball" id="blue">&nbsp;</div> </div> </header> <main> <div id="writer-div"> <form> <input id="writing-area" type="text" rows="1" placeholder="Lets get this out of the way..." maxlength="50" spellcheck="true" autofocus> <button class='default-btn'>+</button> </form> </div> </main> <div id="bottom-header"> <h1 id="output-h1">The current agenda... <hr id="splitter"> </h1> </div> <section id="output-section"> <div class="todo-div"> <h1 class="text-content">Mow the lawn</h1> <button class="delete-btn">x</button> <p class="date-p">mm/dd/yyyy</p> </div> <div class="todo-div"> <h1 class="text-content">Mow the lawn</h1> <button class="delete-btn">x</button> <p class="date-p">mm/dd/yyyy</p> </div> </section> <script src="/toDo.js"></script> </body> </html>

Unrelated to your problem:

  • input elements do not have a closing tag </input>

here is some improvements in your html and js file. we provide each inserted div an id based on arrayOfText length so we can direct access id and used it with combine todo-div + id and remove particular div from its own parent.

 "use strict"; const outputSection = document.querySelector("#output-section"); outputSection.innerHTML = ""; const writingArea = document.querySelector("#writing-area"); const publishBtn = document.querySelector(".default-btn"); const deleteBtns = document.getElementsByClassName("delete-btn"); const allToDoDivs = document.getElementsByClassName("todo"); const arrayOfText = []; const cutAndPrintFunc = function (e) { e.preventDefault(); //take writing in and print it to the current agenda // clear the writing area if (writingArea.value != "") { const date = new Date(); const month = String(date.getMonth() + 1).padStart(2, "0"); const day = String(date.getDay()).padStart(2, "0"); const year = date.getFullYear(); const hour = date.getHours() > 12 ? date.getHours() - 12 : date.getHours(); const AMorPM = date.getHours() > 12 ? "PM" : "AM"; const minute = String(date.getMinutes()).padStart(2, "0"); const indexAdd = (arrayOfText.length === 0) ? 0 : arrayOfText.length; const template = ` <div class="todo todo-div${indexAdd}"> <h1 class="text-content">${writingArea.value}</h1> <button class="delete-btn" onclick="removeTodoDiv(${indexAdd})">x</button> <p class="date-p">${month}/${day}/${year} --- requested @ ${hour}:${minute} ${AMorPM} </p> </div>`; arrayOfText.push(template); outputSection.insertAdjacentHTML("beforeend", template); writingArea.value = ""; Array.from(allToDoDivs).forEach((el, ind) => { if (ind % 2 === 0) { el.style.backgroundColor = "#3ce815"; el.lastElementChild.style.color = "black"; } //-----this does not work // Array.from(allToDoDivs)[ // allToDoDivs.length - 1 // ].children[1].addEventListener("click", () => { // console.log(this); // // arrayOfText.pop(this); // // outputSection.innerHTML = arrayOfText.join(""); // }); }); } }; //publish text by hitting enter or pressing the plus sign in textbox publishBtn.addEventListener("click", cutAndPrintFunc); function removeTodoDiv(index) { const findDiv = document.getElementsByClassName('todo-div' + index)[0]; findDiv.parentNode.removeChild(findDiv); }
 <!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="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link href="https://fonts.googleapis.com/css2?family=Comfortaa&display=swap" rel="stylesheet" /> <link rel="stylesheet" href="/style.css" type="text/css" /> <title>Griffin's ToDo List</title> </head> <body> <header> <h1> Welcome to <em style="text-decoration: underline">Griffin's</em> To-Do List </h1> <div id="mini-flex-div"> <div class="ball" id="blue">&nbsp;</div> <div class="ball" id="orange">&nbsp;</div> <div class="ball" id="purple">&nbsp;</div> <p>What needs to be done today...</p> <div class="ball" id="purple">&nbsp;</div> <div class="ball" id="orange">&nbsp;</div> <div class="ball" id="blue">&nbsp;</div> </div> </header> <main> <div id="writer-div"> <form> <input id="writing-area" type="text" rows="1" placeholder="Lets get this out of the way..." maxlength="50" spellcheck="true" autofocus></input> <button class='default-btn'>+</button> </form> </div> </main> <div id="bottom-header"> <h1 id="output-h1">The current agenda... <hr id="splitter"> </h1> </div> <section id="output-section"> <!-- <div class="todo-div"> <h1 class="text-content">Mow the lawn</h1> <button class="delete-btn">x</button> <p class="date-p">mm/dd/yyyy</p> </div> <div class="todo-div"> <h1 class="text-content">Mow the lawn</h1> <button class="delete-btn">x</button> <p class="date-p">mm/dd/yyyy</p> </div> --> </section> <script src="./index.js"></script> </body> </html>

If you simply wish to remove the item from the list, start at the clicked button, use parentNode to find the "grand" parent (parent's parent) element, and remove, removeChild , the button's parent element:

 // get all buttons and add a click event listener document.querySelectorAll("button.delete-btn").forEach(btn => btn.addEventListener("click", evt => { // get the button's "grandparent", and remove the parent evt.target.parentNode.parentNode.removeChild(evt.target.parentNode); } ))
 <!-- SAMPLE TO DO LIST --> <section id="output-section"> <div class="todo-div" style="background-color: rgb(60, 232, 21);"> <h1 class="text-content">abc</h1> <button class="delete-btn">x</button> <p class="date-p" style="color: black;">06/00/2022 --- requested @ 7:49 AM </p> </div> <div class="todo-div"> <h1 class="text-content">def</h1> <button class="delete-btn">x</button> <p class="date-p">06/00/2022 --- requested @ 7:49 AM </p> </div> <div class="todo-div" style="background-color: rgb(60, 232, 21);"> <h1 class="text-content">ghi</h1> <button class="delete-btn">x</button> <p class="date-p" style="color: black;">06/00/2022 --- requested @ 7:49 AM </p> </div> </section>

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM