Search code examples
javascriptinnerhtml

Is it possible to get the innerhtml value from the first column in the table by clicking on a button on the last column


The table has on the end of each line a wastebasket button, i need to have the value from the first column on that line when the wastebasket button gets clicked.

Now i'm trying to get the value with .queryselectorAll in the for loop to add eventlisteners to the buttons.

This is what the table looks like:

const verwerkDatatable = function(data) {
  console.log(data);
  const table = document.querySelector('.js-table');
  table.innerHTML = `<tr class="js-table-header">
  <td>Naam:</td>
  <td>Toevoegdatum:</td>
  <td>Vervaldatum:</td>
  <td>Aantal:</td>
  <td class="js-delete">Verwijderen:</td>
</tr>`;
  for (let object of data) {
    const amount = object.amount;
    const name = object.name;
    const addDate = object.date;
    const exDate = object.expirationDate;
    table.innerHTML += `<tr>
  <td class="js-name">${name}</td>
  <td>${addDate}</td>
  <td>${exDate}</td>
  <td>${amount}</td>
  <td class="js-delete js-listendelete"> <svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path d="M3 8v16h18v-16h-18zm5 12c0 .552-.448 1-1 1s-1-.448-1-1v-8c0-.552.448-1 1-1s1 .448 1 1v8zm5 0c0 .552-.448 1-1 1s-1-.448-1-1v-8c0-.552.448-1 1-1s1 .448 1 1v8zm5 0c0 .552-.448 1-1 1s-1-.448-1-1v-8c0-.552.448-1 1-1s1 .448 1 1v8zm4-15.375l-.409 1.958-19.591-4.099.409-1.958 5.528 1.099c.881.185 1.82-.742 2.004-1.625l5.204 1.086c-.184.882.307 2.107 1.189 2.291l5.666 1.248z"/></svg></td>
</tr>`;
  }
  listenToTrash();
};

This is how i try to get the value from the first line:

const listenToTrashes = function(){
  const listendel = document.querySelectorAll('.js-listendelete')
  const name = document.querySelectorAll('.js-name')
  let i
  for (i = 0; i < listendel.length; i++) {
    listendel[i].addEventListener('click', function(){
      console.log('click')
      console.log(name[i].innerHTML)

    })
  }

I need to have the value of the first column at the corresponding line of the button that was clicked


Solution

  • There are two problems there:

    1. i will not be the value you expect in the callback because you declared it outside the loop. See this question's answers for why, but basically, you'd put the let inside the for statement in order to make the i your event handlers close over be relevant to the handler. But, there's no need for that, just use this inside the handler instead.

    2. You're relying on the number of .js-name elements to be exactly the same as the number of .js-listendelete elements. Maybe that's reliable, but there's a more reliable way.

    And optionally:

    1. Hooking the handlers directly to the elements is fragile; if you add more elements later, you have to remember to hook them up.

    What I'd do instead is use event delegation and then traversing the DOM:

    • Event delegation: hook click on the table (or table body) and then see if the event passed through a .js-listendelete element on route to the body as it ubbled.

    • Traversing the DOM: If it did, I'd use parentNode or closest() to go up to the row, then get the row's first td.

    Here's an idea what that would look like:

    document.querySelector("selector-for-your-table").addEventListener("click", function(event) {
        const delButton = event.target.closest(".js-listendelete");
        if (delButton && this.contains(delButton)) {
            const firstCell = delButton.closest("tr").querySelector("td");
            if (firstCell) {
                // Use firstCell.innerHTML here
            }
        }
    });
    

    That uses closest on the event.target to find the .js-listendelete that the click started in or passed through. If it returns non-null, we then ensure that what it found is within the table (this.contains(delButton)). Then we find the row containing it and its first cell. (If you like, you can use .cells[0] instead of .querySelector("td"). Those 1990's style accessors have been standardized.)

    Then you have just one event handler, on the table, which handles all the buttons, and handles them by working within the DOM tree rather than assuming parallel lists of nodes are really parallel.

    Note that closest is vaguely modern, you may need a polyfill depending on your target browsers.