Mariana_the_Mermaid
Mariana_the_Mermaid

Reputation: 25

How can I make two buttons with the same function work?

and thank you for your time. Since I've added two+ buttons (run the code and press the "add table" button), all it does is add two new rows to the first table, and the subsequent buttons don't work. I've tried calling the classes, using the loop, and putting the code where it should be, but it still refuses. Here is my code:

<!DOCTYPE html>
<html>
<head>
  <link rel="stylesheet" type="text/css" href="WELPPproto.css">
</head>
<body>
<h1 style="font-family:verdana">Word List</h1>
<table id="list">
  <tr>
    <th scope="col">Word</th>
    <th scope="col">English</th>
    <th scope="col">Pronunciation</th>
    <th scope="col"><button class="deletethismaybe" id="deletethismaybe" type="button" title="delete this table">X</button></th>
  </tr>
  <tfoot>
    <tr>
      <div class="boxy_gril">
        <td><input type="text" id="w" class="w" required /></td>
        <td><input type="text" id="m" class="m" required /></td>
        <td><input type="text" id="p" class="p" /></td>
      </div>
    </tr>
    <tr>
      <td colspan="3"><div class="button_boi"><button type="button" class="button_boi" id="add">Enter</button>
</div></td>
    </tr>
  </tfoot>
</table>
<div id="ntable" class="ntable" >
  <section>
    
  </section>
</div>
  <br>
  <br>
  <button class="button_gril" id="addtable">Add Table</button>
<script>
document.getElementById("addtable").onclick = function() {
  let puttable = document.getElementById("ntable");
  let section = puttable.querySelector('section');

  let tableHTML = '<br><br>' + '<table id="list">' + '<tr>' +
    '<th scope="col">' + 'Word' + '</td>' +
    '<th scope="col">' + 'English' + '</th>' +
    '<th scope="col">' + 'Pronunciation' + '</th>' + '<th><button class="deletethismaybe" id="deletethismaybe" type="button" title="delete this table">X</button></th>' + 
    '</tr>' +
    '<tfoot><tr><div class="boxy_gril">' + 
    '<td><input type="text" id="w" class="w" required /></td>'+
    '<td><input type="text" id="m" class="m" required />' + 
    '</td><td><input type="text" id="p" class="p" /></td>' + 
    '</div></tr>' + '<tr>' + '<td colspan="3">' + '<div class="button_boi">' + '<button type="button" class="button_boi" id="add">Enter</button>' + '</div>' + '</td>'+ '</tr>' + '</tfoot>' + '</table>';
    
   section.insertAdjacentHTML('beforebegin', tableHTML);
  
}

document.addEventListener('click', (e) => {
  let thatTarget = e.target;
  let thatBtn = thatTarget.closest('.deletethismaybe');
  if (thatBtn) {
    e.preventDefault();
    thatTarget.closest('table').remove();
    thatTarget.closest('button').remove();
  }
})

var asdf = document.getElementsByClassName("button_boi");
for (var i = 0; i < asdf.length; i++) {

asdf[i].onclick = function() {
  let listTable = document.getElementById("list");
  let tfoot = listTable.querySelector('tfoot');

  let wordValue = document.getElementById("w").value;
  let engValue = document.getElementById("m").value;
  let pronunValue = document.getElementById("p").value;

  let trHTML = '<tr>' +
    '<td>' + wordValue + '</td>' +
    '<td>' + engValue + '</td>' +
    '<td>' + pronunValue + '</td>' + '<td><button class="deletethis" type="button" title="delete this row">X</button></td>' +
  '</tr>';
  
  tfoot.closest('tfoot').insertAdjacentHTML('beforebegin', trHTML);
}
}

document.addEventListener('click', (e) => {
  let thisTarget = e.target;
  let thisBtn = thisTarget.closest('.deletethis');
  if (thisBtn) {
    e.preventDefault();
    thisTarget.closest('tr').remove();
  }
})

document.getElementsByClassName('.deletethismaybe').onclick = function() {
let thatTarget = e.target;
let thatBtn = thatTarget.closest('.deletethismaybe')
  if (thatBtn) {
    e.preventDefault();
    thatTarget.closest('table').remove();
  }}
</script>
</body>
</html>

Upvotes: 0

Views: 1219

Answers (2)

vee
vee

Reputation: 4755

I think you have to try to understand about JavaScript Event delegation. There are a lot of tutorials about this for example 1, 2, 3, and a lot more on Google.
If you understand how it works, it will be easy and very helpful for you that you don't have to create or call many many event listeners.

Let see my example.

let addNewBtn = document.getElementById('add-new-btn');
addNewBtn.onclick = function() {
    let newBtnHTML = '<button class="addtext" type="button">Add some text</button>';
    document.getElementById('new-button-placeholder').insertAdjacentHTML('beforeend', newBtnHTML);
};


// below is how event delegation works.
// start with listen for click event on root element (`document`)
document.addEventListener('click', (e) => {
    let thisTarget = e.target;
    // the code above is to get `.target` property of clicked element for use later.

    let thisBtn = thisTarget.closest('.addtext');
    // the code above is to get closest button that has `addtext` in the class value. If this button is not exists then it will not go inside the `if` below.

    if (thisBtn) {
        // if this button exists.
        e.preventDefault();// this is for prevent default action in case of form submit. It is no need in this example but just in case you may have to use it later.

        // now add some text to `.debug` HTML element.
        let someText = 'Hello world';
        document.querySelector('.debug').insertAdjacentHTML('beforeend', '<p>' + someText + '</p>');
    }
    // if button is not exists, it will be ignore and has nothing to work here anymore.
});
.debug {
    border: 2px dashed #ccc;
    margin-bottom: 20px;
    padding: 10px;
}
<div class="debug"></div>
<button class="addtext" type="button">Add some text</button>
<button id="add-new-btn" type="button">Add new button that will be clicked and add some text</button>
<hr>
<div id="new-button-placeholder"></div>

Please read the code comment above because I was described everything step by step.
The example code above will work when you click on Add some text and Add new button that will be clicked and add some text buttons. The newly added buttons will be work the same way as existing button without to call or add any new event listener.

This is how Event delegation works.


Now with your work.

  1. The HTML that will be dynamically add by JS should not use the same id. The delete button with id="deletethismaybe" or anything with id=".." that has the same value when you add should be omitted. Use class=".." instead. This is for valid HTML.
  2. Use the descriptive names on everything if possible. No deletethismaybe, or thatBtn, etc because you will confuse yourself in the future.
  3. The td, or th must be inside tr only NOT inside div. So, <div class="boxy_gril"> is invalid HTML!

document.getElementById("addtable").onclick = function() {
  let puttable = document.getElementById("ntable");
  let section = puttable.querySelector('section');

  let tableHTML = '<br><br>' + '<table class="list">' + '<tr>' +
    '<th scope="col">' + 'Word' + '</td>' +
    '<th scope="col">' + 'English' + '</th>' +
    '<th scope="col">' + 'Pronunciation' + '</th>' + '<th><button class="delete-table" type="button" title="delete this table">X</button></th>' +
    '</tr>' +
    '<tfoot><tr>' +
    '<td><input type="text" class="w" required /></td>' +
    '<td><input type="text" class="m" required />' +
    '</td><td><input type="text" class="p" /></td>' +
    '</tr>' + '<tr>' + '<td colspan="3">' + '<div class="button_boi">' + '<button type="button" class="button_boi addrow">Enter</button>' + '</div>' + '</td>' + '</tr>' + '</tfoot>' + '</table>';

  section.insertAdjacentHTML('beforebegin', tableHTML);
}

// listen click event from root element (`document`).
document.addEventListener('click', (e) => {
  let thisTarget = e.target;

  // work with delete table button.
  let deleteTableBtn = thisTarget.closest('.delete-table');
  if (deleteTableBtn) {
    // if delete button exists.
    e.preventDefault();
    thisTarget.closest('table').remove();
  }
  // end

  // work with add row button.
  let addRowBtn = thisTarget.closest('.addrow');
  if (addRowBtn) {
    // if add row button exists.
    e.preventDefault();
    // get closest table element for use later.
    let thisTable = addRowBtn.closest('table');
    // get input values that is under this table where add button was clicked.
    let wordValue = thisTable.querySelector('.w').value;
    let engValue = thisTable.querySelector('.m').value;
    let pronunValue = thisTable.querySelector('.p').value;
    // generate new table row (`tr`)
    let trHTML = '<tr>' +
      '<td>' + wordValue + '</td>' +
      '<td>' + engValue + '</td>' +
      '<td>' + pronunValue + '</td>' + '<td><button class="delete-row" type="button" title="delete this row">X</button></td>' +
      '</tr>';
    thisTable.querySelector('tfoot').insertAdjacentHTML('beforebegin', trHTML);
  }
  // end

  // work with delete row button.
  let deleteRowBtn = thisTarget.closest('.delete-row');
  if (deleteRowBtn) {
    // if delete row button exists.
    e.preventDefault();
    thisTarget.closest('tr').remove();
  }
  // end
})
<h1 style="font-family:verdana">Word List</h1>
<table class="list">
  <tr>
    <th scope="col">Word</th>
    <th scope="col">English</th>
    <th scope="col">Pronunciation</th>
    <th scope="col"><button class="delete-table" type="button" title="delete this table">X</button></th>
  </tr>
  <tfoot>
    <tr>
        <td><input type="text" id="w" class="w" required /></td>
        <td><input type="text" id="m" class="m" required /></td>
        <td><input type="text" id="p" class="p" /></td>
    </tr>
    <tr>
      <td colspan="3">
        <div class="button_boi"><button type="button" class="button_boi addrow">Enter</button>
        </div>
      </td>
    </tr>
  </tfoot>
</table>
<div id="ntable" class="ntable">
  <section>

  </section>
</div>
<br>
<br>
<button class="button_gril" id="addtable">Add Table</button>

From the code above you will see that I use only one event listener and detect that what button does it come form and work with it inside if condition if button exists.

See it in jsfiddle.

Again: Please try to understand about Event delegation as I described from the first because I believe that it will be useful for you.

Upvotes: 0

unspeakable29
unspeakable29

Reputation: 765

That's because the event listeners you created only listens to those that have already been created initially. When new elements get appended in the DOM, you will have to add another event listeners to them as well.

Here's an example on how to do it:

<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>
  </head>
  <body>
    <ul id="lists">
      <li class="list-item">
        <div>List #1</div>
        <button class="btn-delete">Delete</button>
      </li>
    </ul>
    <div>
      <button id="btn-add">Add new item to list</button>
    </div>

    <script>
      const listsEl = document.getElementById('lists');

      // Delete button elements
      let deleteBtnEls = document.querySelectorAll('.btn-delete');
      const deleteBtnOnClick = (e) => {
        const listItemEl = e.target.closest('.list-item');

        listsEl.removeChild(listItemEl);
      };
      const removeEventListeners = () => {
        deleteBtnEls.forEach((deleteBtnEl) => {
          deleteBtnEl.removeEventListener('click', deleteBtnOnClick);
        });
      };
      const updateEventListeners = () => {
        // remove existing event listeners to prevent duplicate event listeners
        removeEventListeners();

        // get the updated list of delete button elements
        deleteBtnEls = document.querySelectorAll('.btn-delete');

        deleteBtnEls.forEach((deleteBtnEl) => {
          deleteBtnEl.addEventListener('click', deleteBtnOnClick);
        });
      };

      // Add new item button element
      const addBtnEl = document.getElementById('btn-add');

      addBtnEl.addEventListener('click', () => {
        const newListItemEl = document.createElement('li');

        newListItemEl.className = 'list-item';
        newListItemEl.innerHTML = `
          <div>List #${listsEl.childElementCount + 1}</div>
          <button class="btn-delete">Delete</button>
        `;

        listsEl.appendChild(newListItemEl);

        updateEventListeners();
      });

      // Initial call
      updateEventListeners();
    </script>
  </body>
</html>

Upvotes: 1

Related Questions