Why is dataset undefined sometimes?

Viewed 49

Why is const filter undefined sometimes when i press it..I have used data-filter on buttons to sort store items..but sometimes when i press a button with dataset filter i get undefined

const buttons = document.querySelectorAll('.filter-btn');
const storeItems = document.querySelectorAll('.store-item');

buttons.forEach((button) => {
  button.addEventListener('click', (e) => {
    e.preventDefault()

    const filter = e.target.dataset.filter
    console.log(filter)

    storeItems.forEach((item) => {
      if (filter === 'all') {
        item.style.display = 'block'
      } else {
        if (item.classList.contains(filter)) {
          item.style.display = 'block'
        } else {
          item.style.display = 'none'
        }
      }
    })
  })
})
.img-wrap img {
  width : 300px;
  }
<div class="container-fluid store-wrap">
  <div class="store-heading">
    <h1>OUR <span>STORE</span></h1>

    <div class="button-wrap">
      <button data-filter="all" class="filter-btn"><p>ALL</p></button>
      <button data-filter="cakes" class="filter-btn"><p>CAKES</p></button>
      <button data-filter="cupcakes" class="filter-btn"><p>CUPCAKES</p></button>
      <button data-filter="sweets" class="filter-btn"><p>SWEETS</p></button>
      <button data-filter="doughnuts" class="filter-btn"><p>DOUGHNUTS</p></button>
    </div>
    <div class="search-wrap">
      <div class="icon-wrap">
        <i class="fa-solid fa-magnifying-glass"></i>
      </div>
      <input type="text" placeholder="Item...">
    </div>
  </div>
  <div class="row store">
    <div class="col-lg store-item cupcakes" data-item="cupcakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1614707267537-b85aaf00c4b7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cupcake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cupcakes" data-item="cupcakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1603532648955-039310d9ed75?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cupcake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cakes" data-item="cakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1578985545062-69928b1d9587?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1089&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cakes" data-item="sweets">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1600359756098-8bc52195bbf4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Sweets</h3>
        <h3>$5</h3>
      </div>
    </div>

  </div>
  <div class="row store">
    <div class="col-lg store-item doughnuts" data-item="doughnuts">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1533910534207-90f31029a78e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Doughnuts</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cakes" data-item="cakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1602351447937-745cb720612f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=686&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cupcakes" data-item="cupcakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1615837136007-701de6015cfb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cupcakes</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item sweets" data-item="sweets">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1600359746315-119f1360d663?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Sweets</h3>
        <h3>$5</h3>
      </div>
    </div>
  </div>
</div>

2 Answers

e.target will refer to the innermost item clicked. If you add an event listener to the container, and the container has a child element, e.target may refer to the container (if you clicked outside the child), or it may refer to the child (if you clicked inside the child). That's what's happening here. If you click directly on one of the texts inside the button, you'll be clicking on a <p> tag, not the button - and that'll be the target.

<button data-filter="all" class="filter-btn"><p>ALL</p></button>
                                             ^^^^^^^^^^

Refer to the button you already have in scope instead of to e.target.

const buttons = document.querySelectorAll('.filter-btn');
const storeItems = document.querySelectorAll('.store-item');

buttons.forEach((button) => {
  button.addEventListener('click', (e) => {
    e.preventDefault()

    const { filter } = button.dataset;
    console.log(filter)

    storeItems.forEach((item) => {
      if (filter === 'all') {
        item.style.display = 'block'
      } else {
        if (item.classList.contains(filter)) {
          item.style.display = 'block'
        } else {
          item.style.display = 'none'
        }
      }
    })
  })
})
.img-wrap img {
  width : 300px;
  }
<div class="container-fluid store-wrap">
  <div class="store-heading">
    <h1>OUR <span>STORE</span></h1>

    <div class="button-wrap">
      <button data-filter="all" class="filter-btn"><p>ALL</p></button>
      <button data-filter="cakes" class="filter-btn"><p>CAKES</p></button>
      <button data-filter="cupcakes" class="filter-btn"><p>CUPCAKES</p></button>
      <button data-filter="sweets" class="filter-btn"><p>SWEETS</p></button>
      <button data-filter="doughnuts" class="filter-btn"><p>DOUGHNUTS</p></button>
    </div>
    <div class="search-wrap">
      <div class="icon-wrap">
        <i class="fa-solid fa-magnifying-glass"></i>
      </div>
      <input type="text" placeholder="Item...">
    </div>
  </div>
  <div class="row store">
    <div class="col-lg store-item cupcakes" data-item="cupcakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1614707267537-b85aaf00c4b7?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cupcake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cupcakes" data-item="cupcakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1603532648955-039310d9ed75?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cupcake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cakes" data-item="cakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1578985545062-69928b1d9587?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=1089&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cakes" data-item="sweets">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1600359756098-8bc52195bbf4?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Sweets</h3>
        <h3>$5</h3>
      </div>
    </div>

  </div>
  <div class="row store">
    <div class="col-lg store-item doughnuts" data-item="doughnuts">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1533910534207-90f31029a78e?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Doughnuts</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cakes" data-item="cakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1602351447937-745cb720612f?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=686&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cake</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item cupcakes" data-item="cupcakes">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1615837136007-701de6015cfb?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=687&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Cupcakes</h3>
        <h3>$5</h3>
      </div>
    </div>
    <div class="col-lg store-item sweets" data-item="sweets">
      <div class="img-wrap">
        <img src="https://images.unsplash.com/photo-1600359746315-119f1360d663?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1wYWdlfHx8fGVufDB8fHx8&auto=format&fit=crop&w=688&q=80" alt="">
        <i class="fa-solid fa-cart-shopping"></i>
      </div>
      <div class="name-price">
        <h3>Sweets</h3>
        <h3>$5</h3>
      </div>
    </div>
  </div>
</div>

If you had to gain another reference to the element you attached the event listener to and didn't have button already in scope, you could use e.currentTarget instead of e.target - .target will refer to the innermost element (the one that the event was dispatched to), but e.currentTarget will refer to the element the listener is attached to.

The problem is occoured for event deligation. You have a p tag in button. So, for event deligatoin, sometimes click goes to the p tag instead of button. You can fix the issue in this way-

const filter = e.target.closest("button").dataset.filter

Related