Search code examples
javascriptaddeventlistenerevent-bubbling

bug removing an entire row in a table using addEventListener


I need to remove an entire row in a table by clicking into a cell with the tag (remove), it works, but if I click in any other cell, the row is removed too. here is the HTML and JS code below to demonstrate using event bubbling aproach:

var table1 = document.querySelector("#tableOne");

table1.addEventListener("click", function(event) {
  event.preventDefault();
  event.target.parentNode.parentNode.remove();
});
<html>
<head></head>
<body>
   <table>
          <thead>
            <tr class="product">
              <td></td>
              <td>Name</td>
              <td>Amount</td>
              <td>Price</td>
              <td>Total</td>
              <td><a href="" class="removeItem">(remove)</a></td>
            </tr>
          </thead>
          <tbody id="tableOne">
            <tr class="product">
              <td><img src="imagens/tablet.jpg"></td>
              <td>Tablet miPad 18</td>
              <td>1</td>
              <td>499.99</td>
              <td class="item-total">499.99</td>
              <td><a href="" class="removeItem">(remove)</a></td>
            </tr>
            <tr class="product">
              <td><img src="imagens/phone.png"></td>
              <td>Telephone miPhone 18</td>
              <td>2</td>
              <td>199.99</td>
              <td class="item-total">399.98</td>
              <td><a href="" class="removeItem">(remove)</a></td>
            </tr>
            <tr class="product">
              <td><img src="imagens/shoe.jpg"></td>
              <td>Shoe</td>
              <td>1</td>
              <td>99.99</td>
              <td class="item-total">99.99</td>
              <td><a href="" class="removeItem">(remove)</a></td>
            </tr>
           </tbody>
          </table>
         </body>
        </html>

the expected result is to remove the row only if I click on (remove) If i could have some way to add a EventListener to every .removeItem would be great. Thanks everyone and Happy Easter!


Solution

  • You can filter events to only those where the target is a removeItem link:

    var table1 = document.getElementById('tableOne');
    
    table1.addEventListener('click', function (event) {
      if (!event.target.classList.contains('removeItem')) {
        return;
      }
    
      event.target.parentNode.parentNode.remove();
      event.preventDefault();
    });
    

    but keep in mind that only works if the link is guaranteed to be the target when it’s clicked, i.e. when the link has no element children. Given that problem and jQuery (yeah, I know), this is more reliable:

    $("#tableOne").on('click', ".removeItem", function (e) {
      $(this).closest(".product").remove();
      e.preventDefault();
    });
    

    If the table doesn’t have rows added dynamically, you can add event listeners to every one (questionable, but convenient):

    var removeLinks = document.getElementsByClassName('removeItem');
    
    for (var i = 0; i < removeLinks.length; i++) {
      removeLinks[i].addEventListener('click', function (e) {
        this.parentNode.parentNode.remove();
        e.preventDefault();
      });
    }
    

    and it’s possible to also bring the jQuery convenience over:

    function closest(className, element) {
      while (element && element.nodeType === 1) {
        if (element.classList.contains(className)) {
          return element;
        }
      }
    
      return null;
    }
    
    var table1 = document.getElementById('tableOne');
    
    table1.addEventListener('click', function (e) {
      var link = closest('removeItem', e.target);
      var row = closest('product', link);
    
      if (!link) {
        return;
      }
    
      row.remove();
      e.preventDefault();
    });