Home > OS >  How do I handle multiple created buttons with JavaScript in a ToDo web script that all have the same
How do I handle multiple created buttons with JavaScript in a ToDo web script that all have the same

Time:06-27

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.

enter image description here

"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 >
          <h1 >${writingArea.value}</h1>
          <button >x</button>
          <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  id="blue">&nbsp;</div>
        <div  id="orange">&nbsp;</div>
        <div  id="purple">&nbsp;</div>
        <p>What needs to be done today...</p>
        <div  id="purple">&nbsp;</div>
        <div  id="orange">&nbsp;</div>
        <div  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 >
            <h1 >Mow the lawn</h1>
            <button >x</button>
            <p >mm/dd/yyyy</p>
        </div>
        <div >
            <h1 >Mow the lawn</h1>
            <button >x</button>
            <p >mm/dd/yyyy</p>
        </div>
    </section>

    <script src="/toDo.js"></script>
  </body>
</html>

CodePudding user response:

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 >${writingArea.value}</h1>
          <button >x</button>
          <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  id="blue">&nbsp;</div>
      <div  id="orange">&nbsp;</div>
      <div  id="purple">&nbsp;</div>
      <p>What needs to be done today...</p>
      <div  id="purple">&nbsp;</div>
      <div  id="orange">&nbsp;</div>
      <div  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 >
      <h1 >Mow the lawn</h1>
      <button >x</button>
      <p >mm/dd/yyyy</p>
    </div>
    <div >
      <h1 >Mow the lawn</h1>
      <button >x</button>
      <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>

CodePudding user response:

here is some improvements in your html and js file.

"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 >
          <h1 >${writingArea.value}</h1>
          <button  onclick="removeTodoDiv(${indexAdd})">x</button>
          <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  id="blue">&nbsp;</div>
      <div  id="orange">&nbsp;</div>
      <div  id="purple">&nbsp;</div>
      <p>What needs to be done today...</p>
      <div  id="purple">&nbsp;</div>
      <div  id="orange">&nbsp;</div>
      <div  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 >
            <h1 >Mow the lawn</h1>
            <button >x</button>
            <p >mm/dd/yyyy</p>
        </div>
        <div >
            <h1 >Mow the lawn</h1>
            <button >x</button>
            <p >mm/dd/yyyy</p>
        </div> -->
  </section>

  <script src="./index.js"></script>
</body>

</html>

CodePudding user response:

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  style="background-color: rgb(60, 232, 21);">
    <h1 >abc</h1>
    <button >x</button>
    <p  style="color: black;">06/00/2022 --- requested @ 7:49 AM </p>
  </div>
  <div >
    <h1 >def</h1>
    <button >x</button>
    <p >06/00/2022 --- requested @ 7:49 AM </p>
  </div>
  <div  style="background-color: rgb(60, 232, 21);">
    <h1 >ghi</h1>
    <button >x</button>
    <p  style="color: black;">06/00/2022 --- requested @ 7:49 AM </p>
  </div>
</section>

  • Related